前回記事の続き:DRM完全解析 - ADD_FB (3)
この記事は次のブログ投稿を参照しています。
どうもありがとうございます!
前回は、drm_mode_addfb関数の最初のステップと最初の関数drm_core_check_featureについて説明しました。今回は引き続き drm_mode_addfb 関数を解析していきます。理解を容易にするために、次のようにコードを drivers/gpu/drm/drm_framebuffer.c に再度投稿します。
/**
* drm_mode_addfb - add an FB to the graphics configuration
* @dev: drm device for the ioctl
* @or: pointer to request structure
* @file_priv: drm file
*
* Add a new FB to the specified CRTC, given a user request. This is the
* original addfb ioctl which only supported RGB formats.
*
* Called by the user via ioctl, or by an in-kernel client.
*
* Returns:
* Zero on success, negative errno on failure.
*/
int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
struct drm_file *file_priv)
{
struct drm_mode_fb_cmd2 r = {};
int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
if (r.pixel_format == DRM_FORMAT_INVALID) {
drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
return -EINVAL;
}
/* convert to new format and call new ioctl */
r.fb_id = or->fb_id;
r.width = or->width;
r.height = or->height;
r.pitches[0] = or->pitch;
r.handles[0] = or->handle;
ret = drm_mode_addfb2(dev, &r, file_priv);
if (ret)
return ret;
or->fb_id = r.fb_id;
return 0;
}
2 番目のステップは、drm_driver_legacy_fb_format 関数を呼び出してピクセル形式を設定することです。drm_driver_fb_format 関数は drivers/gpu/drm/drm_fourcc.c にあり、コードは次のとおりです。
/**
* drm_driver_legacy_fb_format - compute drm fourcc code from legacy description
* @dev: DRM device
* @bpp: bits per pixels
* @depth: bit depth per pixel
*
* Computes a drm fourcc pixel format code for the given @bpp/@depth values.
* Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
* and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
* it returns little endian byte order or host byte order framebuffer formats.
*/
uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
uint32_t bpp, uint32_t depth)
{
uint32_t fmt = drm_mode_legacy_fb_format(bpp, depth);
if (dev->mode_config.quirk_addfb_prefer_host_byte_order) {
if (fmt == DRM_FORMAT_XRGB8888)
fmt = DRM_FORMAT_HOST_XRGB8888;
if (fmt == DRM_FORMAT_ARGB8888)
fmt = DRM_FORMAT_HOST_ARGB8888;
if (fmt == DRM_FORMAT_RGB565)
fmt = DRM_FORMAT_HOST_RGB565;
if (fmt == DRM_FORMAT_XRGB1555)
fmt = DRM_FORMAT_HOST_XRGB1555;
}
if (dev->mode_config.quirk_addfb_prefer_xbgr_30bpp &&
fmt == DRM_FORMAT_XRGB2101010)
fmt = DRM_FORMAT_XBGR2101010;
return fmt;
}
EXPORT_SYMBOL(drm_driver_legacy_fb_format);
drm_driver_legacy_fb_format 関数で最も重要なことは、一番上にある drm_mode_legacy_fb_format 関数を呼び出すことです。コードは次のとおりです。
/**
* drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
* @bpp: bits per pixels
* @depth: bit depth per pixel
*
* Computes a drm fourcc pixel format code for the given @bpp/@depth values.
* Useful in fbdev emulation code, since that deals in those values.
*/
uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
{
uint32_t fmt = DRM_FORMAT_INVALID;
switch (bpp) {
case 1:
if (depth == 1)
fmt = DRM_FORMAT_C1;
break;
case 2:
if (depth == 2)
fmt = DRM_FORMAT_C2;
break;
case 4:
if (depth == 4)
fmt = DRM_FORMAT_C4;
break;
case 8:
if (depth == 8)
fmt = DRM_FORMAT_C8;
break;
case 16:
switch (depth) {
case 15:
fmt = DRM_FORMAT_XRGB1555;
break;
case 16:
fmt = DRM_FORMAT_RGB565;
break;
default:
break;
}
break;
case 24:
if (depth == 24)
fmt = DRM_FORMAT_RGB888;
break;
case 32:
switch (depth) {
case 24:
fmt = DRM_FORMAT_XRGB8888;
break;
case 30:
fmt = DRM_FORMAT_XRGB2101010;
break;
case 32:
fmt = DRM_FORMAT_ARGB8888;
break;
default:
break;
}
break;
default:
break;
}
return fmt;
}
EXPORT_SYMBOL(drm_mode_legacy_fb_format);
drm_mode_legacy_fb_format 関数の機能は一目瞭然で、入力パラメータ bpp と Depth、つまりピクセルあたりのビット数とピクセルあたりのビット幅に従って、fmt のフォーマットを決定して返します。形式には、DRM_FORMAT_RGB888、DRM_FORMAT_ARGB8888 などが含まれます。
drm_driver_legacy_fb_format 関数に戻り、drm_mode_legacy_fb_format によって返された fmt に従って最終的な fmt を決定します。これは、特定の形式に対してマクロ変換を実行してから返すと単純に理解できます。
ここで疑問があります: bpp と深さはどこから来たのでしょうか? コードからわかるように、drm_driver_legacy_fb_format 関数のパラメーターには bpp と Depth が含まれています。
uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
uint32_t bpp, uint32_t depth)
実際のパラメータは drm_mode_addfb 関数が呼び出されるときに渡されます。コード スニペットは次のとおりです。
r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
if (r.pixel_format == DRM_FORMAT_INVALID) {
drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
return -EINVAL;
}
受信 bpp は or->bpp に対応し、深さは or-> Depth に対応することがわかります。
それで、これは何ですか?drm_mode_addfb 関数の説明によれば、 は「リクエスト構造体へのポインタ」、つまりリクエスト構造体へのポインタです。リクエスト構造体は、include/uapi/drm/drm_mode.h で定義されている struct drm_mode_fb_cmd に対応し、コードは次のとおりです。
struct drm_mode_fb_cmd {
__u32 fb_id;
__u32 width;
__u32 height;
__u32 pitch;
__u32 bpp;
__u32 depth;
/* driver specific handle */
__u32 handle;
};
drm_mode_addfb 関数で呼び出された drm_driver_legacy_fb_format 関数 (上記のコード スニペットを参照) が最終的に DRM_FORMAT_INVALID (include/uapi/drm/drm_fourcc.h 内のマクロ定義、値 0) を返す場合、drm_mode_addfb 関数は無効なパラメーターを示す -EINVAL を返します。
ここまでは、drm_mode_addfb 関数の最初のステップである drm_driver_legacy_fb_format 関数を分析しました。残りのステップと機能については、次の記事で引き続き分析します。