目次: Linux
Debian Testingのapt-get updateをしたら、xrdp経由で起動しているX.orgがエラーで起動しなくなりました。こんなエラーが出ています。
[ 1416.016] (EE) [ 1416.016] (EE) Backtrace: [ 1416.016] (EE) 0: /usr/lib/xorg/Xorg (OsLookupColor+0x14d) [0x556fb13c8dad] [ 1416.017] (EE) 1: /lib/x86_64-linux-gnu/libc.so.6 (__sigaction+0x40) [0x7f084f9dad20] [ 1416.017] (EE) 2: /lib/x86_64-linux-gnu/libc.so.6 (pthread_key_delete+0x14c) [0x7f084fa2ee5c] [ 1416.017] (EE) 3: /lib/x86_64-linux-gnu/libc.so.6 (gsignal+0x12) [0x7f084f9dac82] [ 1416.018] (EE) 4: /lib/x86_64-linux-gnu/libc.so.6 (abort+0xd3) [0x7f084f9c34f0] [ 1416.018] (EE) 5: /lib/x86_64-linux-gnu/libc.so.6 (perror+0xcb7) [0x7f084f9c432d] [ 1416.018] (EE) 6: /lib/x86_64-linux-gnu/libc.so.6 (timer_settime+0x395) [0x7f084fa389e5] [ 1416.019] (EE) 7: /lib/x86_64-linux-gnu/libc.so.6 (timer_settime+0x59c) [0x7f084fa38bec] [ 1416.019] (EE) 8: /lib/x86_64-linux-gnu/libc.so.6 (__libc_free+0xb8) [0x7f084fa3d548] [ 1416.019] (EE) 9: /lib/x86_64-linux-gnu/libdrm.so.2 (drmFreeDevice+0x7d) [0x7f084febf13d] [ 1416.020] (EE) 10: /lib/x86_64-linux-gnu/libdrm.so.2 (drmFreeDevices+0x2e) [0x7f084febf2ae] [ 1416.020] (EE) 11: /lib/x86_64-linux-gnu/libnvidia-egl-gbm.so.1 (loadEGLExternalPlatform+0x8a8) [0x7f084477dd18] [ 1416.020] (EE) 12: /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 (NvEglwlaf47906in+0x6e240) [0x7f08404ad480] [ 1416.020] (EE) 13: /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 (NvEglwlaf47906in+0xd73c) [0x7f084044c97c] [ 1416.020] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 1416.020] (EE) 14: /lib/x86_64-linux-gnu/libEGL.so.1 (?+0x0) [0x7f0844a6ead5] [ 1416.020] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 1416.020] (EE) 15: /usr/lib/x86_64-linux-gnu/dri/swrast_dri.so (?+0x0) [0x7f0844aaf3f3] [ 1416.021] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 1416.021] (EE) 16: /usr/lib/xorg/modules/extensions/libglx.so (?+0x0) [0x7f084f65cbe3] [ 1416.021] (EE) unw_get_proc_name failed: no unwind info found [-10] [ 1416.021] (EE) 17: /usr/lib/xorg/modules/extensions/libglx.so (?+0x0) [0x7f084f65ba1f] [ 1416.021] (EE) 18: /usr/lib/xorg/Xorg (_CallCallbacks+0x3c) [0x556fb125002c] [ 1416.021] (EE) 19: /usr/lib/xorg/Xorg (dri3_send_open_reply+0x111f) [0x556fb138334f] [ 1416.021] (EE) 20: /usr/lib/xorg/Xorg (InitExtensions+0x89) [0x556fb12bde29] [ 1416.021] (EE) 21: /usr/lib/xorg/Xorg (InitFonts+0x1f8) [0x556fb124e968] [ 1416.022] (EE) 22: /lib/x86_64-linux-gnu/libc.so.6 (__libc_init_first+0x88) [0x7f084f9c4d68] [ 1416.022] (EE) 23: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0x85) [0x7f084f9c4e25] [ 1416.022] (EE) 24: /usr/lib/xorg/Xorg (_start+0x21) [0x556fb12373f1] [ 1416.022] (EE) [ 1416.022] (EE) Fatal server error: [ 1416.022] (EE) Caught signal 6 (Aborted). Server aborting [ 1416.022] (EE) [ 1416.022] (EE) Please consult the The X.Org Foundation support at http://wiki.x.org for help. [ 1416.022] (EE) Please also check the log file at ".xorgxrdp.10.log" for additional information. [ 1416.022] (EE) [ 1416.022] rdpLeaveVT: [ 1416.022] (EE) Server terminated with error (1). Closing log file.
エラーの原因であるlibEGL_nvidia.soを削除すれば起動しそうだったので、libegl-nvidia0パッケージを消したところX.orgが起動しました。めでたしめでたし……ではありません。どうしてこうなった?
他にも何か起きているだろうか?と調べたらCUDAが使えないし、nvidia-smiがデバイスがないと言っています。NVIDIA系の機能が全滅です。どうやらnvidia.koが消滅していて、GPUカードが認識されなくなったようです。NVIDIAドライバパッケージを再インストールするとこんなメッセージが出ました。
nvidia-kernel-dkms (535.216.03-1) を設定しています ... Loading new nvidia-current-535.216.03 DKMS files... Building for 6.11.10-amd64 Module build for kernel 6.11.10-amd64 was skipped since the kernel headers for this kernel do not seem to be installed.
メッセージはカーネルヘッダをインストールしないとカーネルモジュールがビルドされないとおっしゃっています。カーネルヘッダパッケージlinux-headers-6.11.10-amd64をインストールしたところ無事/lib/modules/6.11.10-amd64/updates/dkms/の下にnvidia-current.ko.xzが生成され、CUDAが復活しました。めでたしめでたし……じゃないんだ、まだ。
X.orgは/dev/driの下にあるデバイスファイルにアクセスするので、DRM関連のドライバも必要です。DRM用のドライバパッケージをインストールするとnvidia-current-drm.ko.xzが生成されます。たしかパッケージ名はnvidia-vdpau-driverだったと思います。
カーネルモジュールが生成されたらmodprobe nvidia-drmでロードすれば/dev/dri/card0が出現します。先ほど削除したlibegl-nvidia0パッケージを再インストールしてもX.orgの起動に失敗しなくなりました。めでたしめでたし。
とはいえxrdp経由で起動していると、DRMが有効でも"unsupported render mode"と言われてしまってHWアクセラレーションが効いてなさそうに見えます。せっかく直したのに悲しいですね……。
PCは起動時にあるキーを押すとBIOS/UEFIの設定画面に遷移します。良く見るパターンはF1, F2, DELキー辺りですが、メーカーごとに完全にバラバラで統一感なしです。私の場合、初めて見るPCのBIOS/UEFI画面を拝みたいときはEsc, F1, F2, F12, DEL辺りを乱打しながら起動します。これでもたまに普通に起動してしまうPCがあってイライラします。
Twitterでこの話に言及したら、いくつか知らないパターンを教えてもらいましたのでそれも紹介します。
こんなものに独自性を出して誰が幸せになるんでしょうか?実に不毛です。PCメーカーとBIOSメーカーはさっさとキーを統一してください……。
目次: Linux
高速なJPEGデコード/エンコードライブラリで有名なlibjpeg-turboですが、ライブラリというかAPIが2系統あります(公式ドキュメントへのリンク、libjpeg-turboのソースコード)。系統その1はlibjpeg(IJG: Independent JPEG Groupのライブラリ)互換のAPIで、系統その2は独自のTurboJPEG APIです。パッケージの名前もややこしくて、しばらくしたら忘れてしまいそうなのでメモしておきます。
各パッケージに含まれるファイルも示しておきます。
libjpeg-turbo8 /usr/lib/aarch64-linux-gnu/libjpeg.so.8 /usr/lib/aarch64-linux-gnu/libjpeg.so.8.2.2 libjpeg-turbo8-dev /usr/include/aarch64-linux-gnu/jconfig.h /usr/include/jerror.h /usr/include/jmorecfg.h /usr/include/jpegint.h /usr/include/jpeglib.h /usr/lib/aarch64-linux-gnu/libjpeg.a /usr/lib/aarch64-linux-gnu/libjpeg.so /usr/lib/aarch64-linux-gnu/pkgconfig/libjpeg.pc libturbojpeg /usr/lib/aarch64-linux-gnu/libturbojpeg.so.0 /usr/lib/aarch64-linux-gnu/libturbojpeg.so.0.2.0 libturbojpeg0-dev /usr/include/turbojpeg.h /usr/lib/aarch64-linux-gnu/libturbojpeg.a /usr/lib/aarch64-linux-gnu/libturbojpeg.so /usr/lib/aarch64-linux-gnu/pkgconfig/libturbojpeg.pc
例としてUbuntu 22.04 AArch64向けのものを示しましたが、他のアーキテクチャやバージョンでも構造は同じです。
目次: Linux
半年経ったら完全に忘れるのでメモします。最近JPEGのデコードエンコードが必要になって色々調べていました。NVIDIA GPUとCUDAを使ってJPEGが扱えるそうで、API名はnvJPEGだそうです(nvJPEGのAPIドキュメント)。
前回まではデコード処理でした。今回はエンコードのAPIをご紹介します。decoupled decodingのような複雑なAPIは存在しないようです。
Raw YUV420の画素データを置くメモリを確保する際はcudaMalloc()ではなく、cudaMallocHost()を使う点がデコードと異なります。エンコードはこんな感じでした。
cudaStream_t stream = nullptr;
nvjpegHandle_t nvj_handle = nullptr;
nvjpegEncoderState_t nvj_state = nullptr;
nvjpegEncoderParams_t nvj_param = nullptr;
nvjpegImage_t inbuf = {0};
uint8_t *jpegbuf = nullptr;
size_t bufsize = 0;
int r;
// Create
cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking);
nvjpegCreateEx(NVJPEG_BACKEND_DEFAULT, nullptr, nullptr, NVJPEG_FLAGS_DEFAULT, &nvj_handle);
nvjpegEncoderStateCreate(nvj_handle, &nvj_state, stream);
nvjpegEncoderParamsCreate(nvj_handle, &nvj_param, stream);
// Set JPEG parameters
nvjpegEncoderParamsSetQuality(nvj_param, 80, stream);
nvjpegEncoderParamsSetSamplingFactors(nvj_param, NVJPEG_CSS_420, stream);
// 2のべき乗境界に切り上げる
#define ALIGN_2N(a, b) (((a) + (b) - 1) & ~((b) - 1))
inbuf.pitch[0] = ALIGN_2N(width, 256);
inbuf.pitch[1] = ALIGN_2N(width, 256);
inbuf.pitch[2] = ALIGN_2N(width, 256);
cudaMallocHost((void **)&inbuf.channel[0], inbuf.pitch[0] * height);
cudaMallocHost((void **)&inbuf.channel[1], inbuf.pitch[1] * height);
cudaMallocHost((void **)&inbuf.channel[2], inbuf.pitch[2] * height);
bufsize = width * height * 3 / 2;
jpegbuf = (uint8_t *)malloc(bufsize);
// YUVデータをinbufにロードする
// 詳細はソースコードを参照
// Encoding
nvjpegChromaSubsampling_t jpegsamp = NVJPEG_CSS_420;
size_t jpegsize = bufsize;
nvjpegEncodeYUV(nvj_handle, nvj_state, nvj_param, &inbuf, jpegsamp, width, height, stream);
nvjpegEncodeRetrieveBitstream(nvj_handle, nvj_state, jpegbuf, &jpegsize, stream);
cudaStreamSynchronize(stream);
// Destroy
free(jpegbuf);
cudaFree(inbuf.channel[0]);
cudaFree(inbuf.channel[1]);
cudaFree(inbuf.channel[2]);
nvjpegEncoderParamsDestroy(nvj_param);
nvjpegEncoderStateDestroy(nvj_state);
nvjpegDestroy(nvj_handle);
cudaStreamDestroy(stream);
YUV420Pのロード部分は本質と関係ないことと、若干長いので省略しました。nvJPEG APIの数は少なくてシンプルです。nvJPEGやNVJPGは機械学習用データ(JPEGファイルのことが多いらしい)を高速に入力するため?らしく、デコード命なのでしょう。エンコードもできるけど主眼ではないから、APIもシンプルなものしかないのかな?
前回同様にソースコードを置いておきます。
使い方はコードの先頭にコメントで書いている通りですが、ここでも説明しておきます。引数はありません。ファイル名test_420.yuvのRaw YUV420ファイルを読み込んで、ファイル名simple_420.jpgのJPEGファイルを書き出します。
$ g++ -g -O2 -Wall 20241120_nvjpeg_simple_enc.cpp -lnvjpeg -lcudart $ ./a.out $ ffplay -i simple_420.jpg
エンコード結果はJPEGです。ffplayでも普段お使いの画像ビューアでも、何を使って確認しても構いません。
目次: Linux
半年経ったら完全に忘れるのでメモします。最近JPEGのデコードエンコードが必要になって色々調べていました。NVIDIA GPUとCUDAを使ってJPEGが扱えるそうで、API名はnvJPEGだそうです(nvJPEGのAPIドキュメント)。
前回ご紹介したdecoupled decodingは呼び出すべきAPI数が多くて、ウワァ……と引いてしまう見た目でした。今回のsimple decodingはその名の通りシンプルです。ちなみにエンコード側もあります。なぜかsimpleに該当するAPIしかなく、decoupled相当のエンコード用APIは存在しないようです。変なの。
Simple decodingはこんな感じでした。Decoupledと比べるとかなりAPIが少なく済みます。
cudaStream_t stream = nullptr;
nvjpegHandle_t nvj_handle = nullptr;
nvjpegJpegState_t nvj_state = nullptr;
nvjpegImage_t outbuf = {0};
uint8_t *img_buf[4] = {nullptr};
int img_stride[4] = {0};
int img_sz[4] = {0};
int r;
// Create
cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking);
nvjpegCreateEx(NVJPEG_BACKEND_DEFAULT, nullptr, nullptr, NVJPEG_FLAGS_DEFAULT, &nvj_handle);
nvjpegJpegStateCreate(nvj_handle, &nvj_state);
//2のべき乗境界に切り上げる
#define ALIGN_2N(a, b) (((a) + (b) - 1) & ~((b) - 1))
outbuf.pitch[0] = ALIGN_2N(width, 256);
outbuf.pitch[1] = ALIGN_2N(width, 256);
outbuf.pitch[2] = ALIGN_2N(width, 256);
cudaMalloc(&outbuf.channel[0], outbuf.pitch[0] * height);
cudaMalloc(&outbuf.channel[1], outbuf.pitch[1] * height);
cudaMalloc(&outbuf.channel[2], outbuf.pitch[2] * height);
img_stride[0] = ALIGN_2N(width, 256);
img_stride[1] = ALIGN_2N(width, 256);
img_stride[2] = ALIGN_2N(width, 256);
img_buf[0] = (uint8_t *)malloc(img_stride[0] * height);
img_buf[1] = (uint8_t *)malloc(img_stride[1] * height);
img_buf[2] = (uint8_t *)malloc(img_stride[2] * height);
//Decoupled phase decoding
nvjpegGetImageInfo(nvj_handle, jpegbuf, jpegsize, &jpegcomps, &jpegsamp, jpegwidths, jpegheights);
nvjpegDecode(nvj_handle, nvj_state, jpegbuf, jpegsize, NVJPEG_OUTPUT_YUV, &outbuf, stream);
cudaStreamSynchronize(stream);
for (int i = 0; i < 3; i++) {
cudaMemcpy2D(img_buf[i], img_stride[i], outbuf.channel[i], outbuf.pitch[i],
width, height, cudaMemcpyDeviceToHost);
}
// Destroy
free(img_buf[0]);
free(img_buf[1]);
free(img_buf[2]);
cudaFree(outbuf.channel[0]);
cudaFree(outbuf.channel[1]);
cudaFree(outbuf.channel[2]);
nvjpegJpegStateDestroy(nvj_state);
nvjpegDestroy(nvj_handle);
cudaStreamDestroy(stream);
1枚だけJPEGをデコードするならこちらの方が断然楽ですね。
前回同様にソースコードを置いておきます。
使い方はコードの先頭にコメントで書いている通りですが、ここでも説明しておきます。引数はありません。ファイル名test_420.jpgのJPEGファイルを読み込んで、ファイル名simple_420.yuvのRawvideoファイルを書き出します。
$ g++ -g -O2 -Wall 20241120_nvjpeg_simple_dec.cpp -lnvjpeg -lcudart $ ./a.out $ ffplay -f rawvideo -video_size 1920x1440 -pixel_format yuv420p -i simple_420.yuv
デコード結果のRawvideoを確認するときはffplayを使うと便利です。
< | 2024 | > | ||||
<< | < | 12 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | - | - | - | - |
合計:
本日: