IGT_GPU_TOOL系列之CRC(一):test_grab_crc
在IGT_GPU_TOOL测试工具中,test_grab_crc是获取CRC值验证图形输出是否正确的重要函数。
一、test_grab_crc
通过创建帧缓冲区、设置显示内容、收集CRC值来验证图形输出的正确性。
static void test_grab_crc(data_t *data, igt_output_t *output, enum pipe pipe,
color_t *fb_color, unsigned int flags, igt_crc_t *crc /* out */)
{
struct igt_fb fb;
drmModeModeInfo *mode;
igt_plane_t *primary;
char *crc_str;
int ret;
/*将指定的输出设备与图形管道绑定*/
igt_output_set_pipe(output, pipe);
/*获取输出设备的主平面(primary plane),通常用于显示帧缓冲区的内容*/
primary = igt_output_get_plane(output, 0);
/*获取当前输出设备的显示模式(分辨率、刷新率等)*/
mode = igt_output_get_mode(output);
/*如果 flags 包含 TEST_POSITION_PARTIALLY_COVERED,表示帧缓冲区部分被覆盖:
创建一个包含多个矩形的帧缓冲区,每个矩形有不同的颜色。*/
if (flags & TEST_POSITION_PARTIALLY_COVERED) {
static const rectangle_t rects[] = {
{ .x = 100, .y = 100, .color = { 0.0, 0.0, 0.0 }},
{ .x = 132, .y = 132, .color = { 0.0, 1.0, 0.0 }},
};
create_fb_for_mode(data, mode, fb_color,
rects, ARRAY_SIZE(rects), &fb);
} else {
/*创建一个单色的帧缓冲区*/
igt_assert_fd(igt_create_color_fb(data->drm_fd,
mode->hdisplay, mode->vdisplay,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_MOD_LINEAR,
fb_color->red, fb_color->green, fb_color->blue,
&fb));
}
/*将创建的帧缓冲区设置到主平面上*/
igt_plane_set_fb(primary, &fb);
ret = igt_display_try_commit2(&data->display, COMMIT_LEGACY);
igt_skip_on(ret != 0);
/*从图形管道中收集CRC值,用于验证帧缓冲区的正确性。*/
igt_pipe_crc_collect_crc(data->pipe_crc, crc);
igt_plane_set_fb(primary, NULL);
igt_display_commit(&data->display);
igt_remove_fb(data->drm_fd, &fb);
/*将CRC值转换为字符串并输出到调试日志中,最后释放字符串内存。*/
crc_str = igt_crc_to_string(crc);
igt_debug("CRC for a %s covered (%.02f,%.02f,%.02f) fb: %s\n",
flags & TEST_POSITION_PARTIALLY_COVERED ? "partially" : "fully",
fb_color->red, fb_color->green, fb_color->blue,
crc_str);
free(crc_str);
}
1.igt_pipe_crc_collect_crc
获取CRC 的值
void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
{
igt_debug_wait_for_keypress("crc");
/*启动图形管道 CRC(循环冗余校验)的收集功能*/
igt_pipe_crc_start(pipe_crc);
/*读取CRC*/
igt_pipe_crc_get_single(pipe_crc, out_crc);
igt_pipe_crc_stop(pipe_crc);
}
void igt_pipe_crc_get_single(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc)
{
read_one_crc(pipe_crc, crc);
crc_sanity_checks(pipe_crc, crc);
}
1.1read_one_crc
主要功能是从图形管道 CRC 源中读取一个 CRC 值。
阻塞模式 vs 非阻塞模式:
**a.阻塞模式:**如果文件描述符处于阻塞模式,当调用 read 等 I/O 操作时,如果没有数据可读,调用会一直等待,直到有数据可读或发生错误。
b.非阻塞模式:如果文件描述符处于非阻塞模式,当调用 read 等 I/O 操作时,如果没有数据可读,调用会立即返回,并返回一个错误。
static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
{
int ret;
/*pipe_crc->crc_fd 是用于读取 CRC 值的文件描述符。
fcntl 是一个系统调用,用于操作文件描述符的属性。
F_SETFL 表示设置文件描述符的标志位。
pipe_crc->flags & ~O_NONBLOCK 的作用是清除 O_NONBLOCK 标志位,即将文件描述符设置为阻塞模式。这意味着如果没有数据可读,read 调用会一直等待,直到有数据可读为止。*/
fcntl(pipe_crc->crc_fd, F_SETFL, pipe_crc->flags & ~O_NONBLOCK);
/*循环会一直进行,直到成功读取到 CRC 值(即 ret 不为 -EINTR)。*/
do {
ret = read_crc(pipe_crc, out);
} while (ret == -EINTR);
/*恢复文件描述符的标志位*/
fcntl(pipe_crc->crc_fd, F_SETFL, pipe_crc->flags);
}
1.2igt_pipe_crc_start
启动图形管道 CRC(循环冗余校验)的收集功能。
void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
{
const char *src = pipe_crc->source;
struct pollfd pfd;
char buf[32];
/* 确保之前的 CRC 收集已经停止,避免残留状态影响当前操作 */
igt_pipe_crc_stop(pipe_crc);
/*重置 FIFO 下溢报告,确保图形管道的 FIFO 状态正常*/
igt_reset_fifo_underrun_reporting(pipe_crc->fd);
/*将 pipe_crc->source 的内容写入控制文件描述符 pipe_crc->ctl_fd*/
igt_assert_eq(write(pipe_crc->ctl_fd, src, strlen(src)), strlen(src));
sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
igt_set_timeout(10, "Opening crc fd, and poll for first CRC.");
/*使用 openat 打开 CRC 数据文件,文件描述符存储在 pipe_crc->crc_fd 中*/
pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
igt_assert(pipe_crc->crc_fd != -1);
pfd.fd = pipe_crc->crc_fd;
pfd.events = POLLIN;
poll(&pfd, 1, -1);
igt_reset_timeout();
errno = 0;
}