Linux libdrm库入门教程

DRM 相关知识链接

1、基础概念介绍:
https://www.cnblogs.com/EaIE099/p/7514293.html

2、api接口说明:
https://docs.nvidia.com/drive/nvvib_docs/NVIDIA%20DRIVE%20Linux%20SDK%20Development%20Guide/baggage/group__direct__rendering__manager.html

DRM库提供的测试工具

modetest用法:
在这里插入图片描述
1、查看状态信息,输入命令:modetest则显示如下信息(省略属性信息)

Encoders:
id      crtc    type    possible crtcs  possible clones
60      59      DSI     0x00000001      0x00000000

Connectors:
id      encoder status          name            size (mm)       modes   encoders
61      60      connected       DSI-1           68x121          1       60
  modes:
        name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
  720x1280 60 720 760 770 810 1280 1302 1306 1317 64000 flags: nhsync, nvsync; type: preferred

CRTCs:
id      fb      pos     size
59      66      (0,0)   (720x1280)
  720x1280 60 720 760 770 810 1280 1302 1306 1317 64000 flags: nhsync, nvsync; type: preferred
 
Planes:
id      crtc    fb      CRTC x,y        x,y     gamma size      possible crtcs
58      59      66      0,0             0,0     0               0x00000001
  formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16

Frame buffers:
id      size    pitch

上面含义是:

  • 1 个connectors:id=61, 最大分辨率为720x1280;
  • 1 个crtc:id=59,最大分辨率为720x1280;
  • 1 个plane:id=58,支持像素格式 XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16。

比如使用RG24(对应RGB888,具体可参见drm_fourcc.h)像素格式测试屏幕显示:

modetest -s 61@59:720x1280@RG24

上述命令执行后的显示效果如下:
在这里插入图片描述

测试用例

  • 工程下载地址:https://download.csdn.net/download/lyy901135/11588539

  • 运行命令:mydrmtest
    在这里插入图片描述

  • 运行效果:先显示一个白屏(1s),然后显示30帧竖直黑白间隔图像(间隔1s)。如下图所示(手机翻拍导致不清晰)
    在这里插入图片描述

  • 代码说明:本示例基于RK1808,最大分辨率为720x1280,仅有一个Connector,一个Crtc,一个Plane。若针对多Plane平台,则还需动态适配显示模式,图像格式,图层等。

/*
 * Author:Francis Fan
 * Date:2019-8-21
 */

#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

#include <drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

#include "util/kms.h"
#include "drm_fourcc.h"
#include "buffers.h"
#include "libdrm_macros.h"

static void debug_save_file(void *ptr, int size, char *path)
{
	FILE *debug_file;
	int ret = 0;

	debug_file = fopen(path, "wb");
	if (!debug_file) {
		printf("DEBUG: open debug file %s failed!\n", path);
		return;		
	}

	ret = fwrite(ptr, 1, size, debug_file);
	if (ret != size)
		printf("DEBUG: save debug file %s failed\n", path);
	else
		printf("DEBUG: save debug file as %s\n", path);

	fclose(debug_file);
}

/* Fill black and white vertical stripe data, like:
 * White | Black | White | Black
 */
static void fill_frame_rgb24_date(unsigned char *ptr, int width, int height, int linesize)
{
	unsigned char *line_ptr = NULL;
	unsigned char d_r = 0, d_g = 0, d_b = 0;

	if (!ptr || (linesize < width)) {
		printf("ERROR: %s invalid args!\n", __func__);
		return;
	}

	for (int i = 0; i < height; i++) {
		line_ptr = ptr + i * linesize;
		for (int j = 0; j < width; j++) {
			if (j < (width / 4)) {
				d_r = 0; d_g = 0; d_b = 0;
			} else if (j < (width / 2)) {
				d_r = 255; d_g = 255; d_b = 255;
			} else if (j < (width * 3 / 4)) {
				d_r = 0; d_g = 0; d_b = 0;
			} else {
				d_r = 255; d_g = 255; d_b = 255;
			}

			*line_ptr = d_r;
			line_ptr++;
			*line_ptr = d_g;
			line_ptr++;
			*line_ptr = d_b;
			line_ptr++;
		}
	}	
}

int main(int argc, char *argv[])
{
	int frame_cnt = 30;
    int width, height;
	int ret = 0;
	int drm_fd = 0;
	int connector_id, crtc_id, plane_id;

	drmModeRes *res = NULL;
	drmModeConnector *conn = NULL;
	drmModeCrtc *crtc = NULL;
	drmModePlaneRes *pres = NULL;
	unsigned int fb_id;

	if (argc == 3) {
		width = atoi(argv[1]);
		height = atoi(argv[2]);
		printf("### Input Resolution:%sx%s --> (%d, %d)\n", argv[1], argv[2], width, height);
	} else {
		width = 720;
		height = 1280;
		printf("### Default Resolution: 720x1280\n");
	}

	printf("### Init drm ...\n");
    drm_fd = util_open(NULL, NULL);
	if (drm_fd < 0) {
		printf("ERROR: drm_open failed!\n");
		return -1;
	}

	/***********************************************************
	 * Get screen infos
	 ***********************************************************/
	if (drmSetClientCap (drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
		printf("ERROR: drmModeGetCrtc failed!\n");
		goto OUT;
	}

	res = drmModeGetResources (drm_fd);
	if (!res) {
		printf("ERROR: drmModeGetResources failed!\n");
		drmClose(drm_fd);
		return -1;
	}

	printf("INFO: count_fbs:%d, count_crtcs:%d, count_encoders:%d, count_connectors:%d \n",
		res->count_fbs, res->count_crtcs, res->count_encoders, res->count_connectors);

	/* This test for only 1 connector and only 1 crtc */
	connector_id = res->connectors[0];
	crtc_id = res->crtcs[0];

	/* Just fort print connector only */
	conn = drmModeGetConnector (drm_fd, connector_id);
	if (!conn) {
		printf("ERROR: drmModeGetConnector failed!\n");
		goto OUT;
	}

	/* Get plane infos */
	pres = drmModeGetPlaneResources (drm_fd);
	if (!pres) {
		printf("ERROR: drmModeGetPlaneResources failed!\n");
		goto OUT;
	}
	/* This test for only 1 plane */
	plane_id = pres->planes[0];

	printf("INFO: connector->name:%s-%u\n", util_lookup_connector_type_name(conn->connector_type),
		conn->connector_type_id);
	printf("INFO: connector id = %d / crtc id = %d / plane id = %d\n",
		connector_id, crtc_id, plane_id);

	/***********************************************************
	 * Start Mode Setting
	 ***********************************************************/
	struct bo *bo;
	drmModeModeInfo *mode;
	/* Max planes:4
	 * handles: dumb buffer handle, create by libdrm api
	 * pitches: real linesize, by Bytes.
	 * offset: every plane offset.
	 */
	unsigned int handles[4] = {0};
	unsigned int pitches[4] = {0};
	unsigned int offsets[4] = {0};
	uint64_t cap = 0;

	/* Support dumb buffer? */
	ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
	if (ret || cap == 0) {
		fprintf(stderr, "ERROR: driver doesn't support the dumb buffer API\n");
		goto OUT;
	}

	/* Create dumb buffer and mmap it */
	bo = bo_create(drm_fd, DRM_FORMAT_RGB888, width, height, handles, pitches, offsets, UTIL_PATTERN_SMPTE);
	if (bo == NULL) {
		printf("ERROR: bo_create failed!\n");
		goto OUT;
	}

	for (int i = 0; i < 4; i++)
		printf("INFO: #%d handles:%d, pitches:%d, offsets:%d\n", i, handles[i], pitches[i], offsets[i]);

	/* Fill date: full screen is white */
	memset(bo->ptr, 255, height * pitches[0]);

	/* Get framebuff id, this id is used by drm api to find the buffer.
	 * Format the display memory, then the drm api knows what format to
	 * display the memory of the drm application.
	 */
	ret = drmModeAddFB2(drm_fd, width, height, DRM_FORMAT_RGB888, handles, pitches, offsets, &fb_id, 0);
	if (ret) {
		printf("ERROR: drmModeAddFB2 failed!\n");
		goto OUT;
	}

	/* Get the crtc display mode. For this test, only 1 mode support. */
	mode = &conn->modes[0];
	printf("INFO: mode->mame:%s, %dx%d, Conn_id:%d, crtc_id:%d\n",
		mode->name, mode->hdisplay, mode->vdisplay, connector_id, crtc_id);

	ret = drmModeSetCrtc(drm_fd, crtc_id, fb_id, 0, 0, (uint32_t *)&connector_id, 1, mode);
	if (ret) {
		printf("ERROR: drmModeSetCrtc failed!\n");
		goto OUT;
	}

	/* XXX: Actually check if this is needed */
	drmModeDirtyFB(drm_fd, fb_id, NULL, 0);

	/* show modeseting effect: full screen white */
	sleep(1);

	/***********************************************************
	 * Start Set plane: show frame to plane
	 ***********************************************************/
	while (frame_cnt--) {
		fill_frame_rgb24_date(bo->ptr, width, height, pitches[0]);
		//debug_save_file(bo->ptr, pitches[0]*height);

		/* note src coords (last 4 args) are in Q16 format */
		if (drmModeSetPlane(drm_fd, plane_id, crtc_id, fb_id,
			0, 0, 0, width, height, 0, 0, width << 16, height << 16)) {
			printf("ERROR: drmModeSetPlane failed! plane_id:%d, fb_id:%d\n", plane_id, fb_id);
			return -1;
		}

		sleep(1);
	}

OUT:
	if (bo) {
		if (bo->ptr)
			drm_munmap(bo->ptr, bo->size);
		bo->ptr = NULL;
		bo_destroy(bo);
	}

	if (pres)
		drmModeFreePlaneResources (pres);
	if (conn)
		drmModeFreeConnector (conn);
	if (res)
		drmModeFreeResources (res);
	if (drm_fd)
		drmClose(drm_fd);

    return 0;
}

交叉编译libdrm是将libdrm在一台计算机上编译成为可在另一台不同体系结构的计算机上运行的目标文件。它通常用于在开发嵌入式系统或跨平台应用程序时。 首先,我们需要了解目标计算机的体系结构和操作系统。然后,我们需要配置交叉编译工具链,以便在本地计算机上编译适用于目标计算机的程序。 接下来,我们需要下载libdrm的源代码。你可以从官方网站或开源代码存储获取最新的稳定版本。解压缩源代码后,进入源代码目录。 配置交叉编译选项是很重要的一步。我们可以使用configure脚本来自动配置编译选项。但在交叉编译情况下,我们需要指定目标体系结构和交叉工具链的路径。例如,对于ARM体系结构的目标计算机,我们可以使用以下命令进行配置: ./configure --host=arm-linux-gnueabi --prefix=/path/to/target 其中,--host选项指定了目标体系结构和操作系统。--prefix选项指定了安装路径,即在目标计算机上安装libdrm文件的位置。 配置完成后,我们可以使用make命令进行编译。交叉编译的关键是指定正确的编译器和工具链,以便将源代码编译为目标体系结构的二进制文件。 make CC=arm-linux-gnueabi-gcc 其中,CC选项指定了交叉编译器的名称。 编译完成后,我们可以使用make install命令将编译好的文件安装到目标计算机上。 make install 在安装完成后,你可以将生成的目标文件复制到目标计算机上,并在应用程序中使用该。 总而言之,交叉编译libdrm需要配置正确的交叉编译选项,并使用交叉编译工具链来编译源代码。通过这种方式,我们可以将libdrm编译为可在不同体系结构的计算机上运行的目标文件。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值