LoginSignup
3
1

More than 5 years have passed since last update.

NV12フォーマットのGEM FLINK名からテクスチャを生成する

Last updated at Posted at 2017-11-24

YUVフォーマット(ここではNV12)のDRMバッファのGEM FLINK名がわかっている状態でそこからテクスチャを生成してみる。

GEM FLINKについては
https://qiita.com/maueki/items/8392decdd36c3fa19117#gem-flink

記載するコードについてはエラー処理は省略している。

EGL, GLの初期化

省略

GBMデバイスオープン

int drv_fd = open("/dev/dri/card0", O_RDWR);
struct gbm_device* gbm = gbm_create_device(drv_fd);

PRIME FD取得

GEM FLINK名はuint32_t nameという変数に格納されているものとする。

struct drm_gem_open gem_open = {};
gem_open.name = name;
drmIoctl(gbm_device_get_fd(gbm), DRM_IOCTL_GEM_OPEN, &gem_open));

struct drm_prime_handle prime_handle = {.handle = gem_open.handle, .flags = 0 /* O_CLOSEXEC */ };
drmIoctl(gbm_device_get_fd(gbm), DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle);

int fd = prime_handle.fd;

fdがPRIME FDとなる

eglImageKHR作成

EGL拡張のEGL_EXT_image_dma_buf_importを使用してPRIME FDからeglImageKHRを取得する。

    EGLint img_attribs[] = {
        EGL_WIDTH,                  <width>,
        EGL_HEIGHT,                 <height>,
        EGL_LINUX_DRM_FOURCC_EXT,   DRM_FORMAT_NV11, /// =0x3231564e,
        EGL_DMA_BUF_PLANE0_FD_EXT,  fd,
        EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
        EGL_DMA_BUF_PLANE0_PITCH_EXT, <一行あたりのバイト数(アライメント注意)>,
        EGL_DMA_BUF_PLANE1_FD_EXT,  fd,
        EGL_DMA_BUF_PLANE1_OFFSET_EXT, <PLANE1の開始位置>,
        EGL_DMA_BUF_PLANE1_PITCH_EXT, <一行あたりのバイト数(PLANE0と同じはず)>,
        EGL_NONE
    };

    EGLImageKHR eglImage = eglCreateImageKHR(egl_dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer)0, img_attribs);

PLANEは2まであって、フォーマットに合わせて使い分ける。NV12の場合はYとUVの2面に分かれているのでPLANE0,PLANE1を使用する。
YUVフォーマットについて詳しくは以下参照
http://klabgames.tech.blog.jp.klab.com/archives/1054828175.html

EGL_DMA_BUF_PLANE1_OFFSET_EXTの値は基本的にEGL_DMA_BUF_PLANE0_PITCH_EXT * EGL_HEIGHTのはずだが、アライメント調整されることがあるので注意(自分の環境だと32の倍数である必要があってかなりハマった)

テクスチャ作成

GL拡張のGL_OES_EGL_image_externalを使用してテクスチャを作成する。

glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);

GL_TEXTURE_2DではなくGL_TEXTURE_EXTERNAL_OESを使っていることに注意。

あとは通常のテクスチャ同様に描画すれば内部でNV12 -> RGBの変換を行ってくれる。

描画時の注意

GL_TEXTURE_EXTERNAL_OESを使っているため、sampler2Dは使用できない。
フラグメントシェーダの先頭に

#extension GL_OES_EGL_image_external: require

を記載し、samplerExternalOESを使用する。texture2D()は同様に使用可能。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1