このブログは、株式会社フィックスターズのエンジニアが、あらゆるテーマについて自由に書いているブログです。
最近のGPUは、動画エンコーダを実装しているものが多いです。
Intel社のGPUは、この動画エンコーダで使われる、ブロック単位での動き予測ハードウェアを、OpenCLから使うことができます。
公式の解説 : https://software.intel.com/en-us/articles/intro-to-motion-estimation-extension-for-opencl
公式のサンプル : https://software.intel.com/en-us/articles/video-motion-estimation-using-opencl
公式のサンプルに気付かないで作ってしまったサンプル : https://bitbucket.org/fixstars/blog/src/95aecef11221e15d291076f815e171a4c7671e35/me/?at=master
手順は以下のとおりです。
clGetExtensionFunctionAddressForPlatform で、 “clCreateAcceleratorINTEL” のポインタを取得します。これは、デバイスが “cl_intel_accelerator” 拡張を持っているときに有効です。
p_clCreateAccelrator = (clCreateAcceleratorINTEL_fn)
clGetExtensionFunctionAddressForPlatform(cl_plt(), "clCreateAcceleratorINTEL");
これを使って、cl_accelerator_intel を作ります。
me_block_typeでブロックサイズを決めます。me_search_path_type で探索範囲を決めます。subpixel_mode は hpel, qpel などが選べるようです。sad_adjust_mode はすいません、よくわかりませんでした。普通にSADの場合は上のようにすればよいと思います。
cl_motion_estimation_desc_intel me_desc = {0};
switch (blk_size) {
case 4:
me_desc.mb_block_type = CL_ME_MB_TYPE_4x4_INTEL;
break;
case 8:
me_desc.mb_block_type = CL_ME_MB_TYPE_8x8_INTEL;
break;
case 16:
me_desc.mb_block_type = CL_ME_MB_TYPE_16x16_INTEL;
break;
default:
printf("blk_size=%d is not supported\n", blk_size);
return -1;
}
switch (radius) {
case 2:
me_desc.search_path_type = CL_ME_SEARCH_PATH_RADIUS_2_2_INTEL;
break;
case 4:
me_desc.search_path_type = CL_ME_SEARCH_PATH_RADIUS_4_4_INTEL;
break;
case 16:
me_desc.search_path_type = CL_ME_SEARCH_PATH_RADIUS_16_12_INTEL;
break;
default:
printf("radius=%d is not supported\n", radius);
return -1;
}
me_desc.subpixel_mode = CL_ME_SUBPIXEL_MODE_INTEGER_INTEL;
me_desc.sad_adjust_mode = CL_ME_SAD_ADJUST_MODE_NONE_INTEL;
cl_int err;
accelerator = p_clCreateAccelrator(gpu_context(),
CL_ACCELERATOR_TYPE_MOTION_ESTIMATION_INTEL,
sizeof(me_desc),
&me_desc,
&err);
block_motion_estimate_intel カーネルを作ります。
cl.hpp を使っているのでわかりづらいですが、OpenCL 1.2には、こういう特殊なカーネルを作る場合のために、 clCreateProgramWithBuiltInKernels というのがあります。これを使っています。
cl::Program me_prog(gpu_context, gpu_devs, "block_motion_estimate_intel");
me_kernel = cl::Kernel(me_prog, "block_motion_estimate_intel");
カーネルに引数を設定します。block_motion_estimate_intelカーネルの引数は、
_kernel void
block_motion_estimate_intel
(
accelerator_intel_t accelerator,
__read_only image2d_t src_image,
__read_only image2d_t ref_image,
__global short2 * prediction_motion_vector_buffer,
__global short2 * motion_vector_buffer,
__global ushort * residuals
);
と、なっていてそれぞれ、
です。
時間を計測したところ、720p で 1.5~3.5[msec] 程度のようです。
簡単に書いた C++(OpenMPあり)だと、i7-4700MQ(2.4GHz 4core 8thread)で 65msecなので、それより20~40倍ぐらい速いですね。SADのBMはSIMDで速くなるのであまり良い比較ではないですが、さすがに20倍にはならないので、速いと言っていいと思います。
Atomのように小さいCPUだとより使うメリットは大きいですね、Atom Z3740 では 720p で、7[msec]程度で実行できるようです。
keisuke.kimura in Livox Mid-360をROS1/ROS2で動かしてみた
Sorry for the delay in replying. I have done SLAM (FAST_LIO) with Livox MID360, but for various reasons I have not be...
Miya in ウエハースケールエンジン向けSimulated Annealingを複数タイルによる並列化で実装しました
作成されたプロファイラがとても良さそうです :) ぜひ詳細を書いていただきたいです!...
Deivaprakash in Livox Mid-360をROS1/ROS2で動かしてみた
Hey guys myself deiva from India currently i am working in this Livox MID360 and eager to knwo whether you have done the...
岩崎システム設計 岩崎 満 in Alveo U50で10G Ethernetを試してみる
仕事の都合で、検索を行い、御社サイトにたどりつきました。 内容は大変参考になりま...
Prabuddhi Wariyapperuma in Livox Mid-360をROS1/ROS2で動かしてみた
This issue was sorted....