驱动开发系列57 - Linux Graphics QXL显卡驱动代码分析(四)显示区域更新

一:概述

前面在介绍了显示模式设置(分辨率,刷新率)之后,本文继续分析下,显示区域的绘制,详细看看虚拟机的画面是如何由QXL显卡绘制出来的。

二:相关数据结构介绍

cpp 复制代码
struct qxl_monitors_config {
    uint16_t count;         // 当前启用的显示器数量(head 数量)
    uint16_t max_allowed;   // 驱动允许的最大显示器数量,如果为 0,表示没有固定限制,由驱动动态决定
    struct qxl_head heads[]; // 每个显示器的配置数组(实际大小为 count)
};
cpp 复制代码
struct qxl_head {
	uint32_t id;           // 显示头(显示器)ID
	uint32_t surface_id;   // 绑定的 QXLSurface ID
	uint32_t width;        // 显示区域的宽度(像素)
	uint32_t height;       // 显示区域的高度(像素)
	uint32_t x;            // 在绑定 surface 上的 X 偏移(起始坐标)
	uint32_t y;            // 在绑定 surface 上的 Y 偏移
	uint32_t flags;        // 标志位,用于额外配置(比如是否启用、旋转等)
};
cpp 复制代码
struct qxl_surface_id {
    uint32_t surface_id; // 表示 QXL 表面(Surface)的唯一标识符。每个表面都会有一个唯一的 ID,用于区分和识别不同的表面。
};
cpp 复制代码
struct qxl_image {
    struct qxl_image_descriptor descriptor;  // 图像的描述符,包含图像的基本信息(例如图像类型、大小等)
    union {  /* 可变长度的数据,根据图像类型选择使用 */
        struct qxl_bitmap bitmap;        // 图像数据,作为位图(bitmap)表示
        struct qxl_encoder_data quic;    // 图像数据,作为 QUIC 编码数据表示(用于高效传输)
        struct qxl_surface_id surface_image; // 图像数据,作为表面图像的 ID 表示(指向一个渲染表面)
    } u;
};
cpp 复制代码
struct qxl_image_descriptor {
    uint64_t id;           // 图像的唯一标识符,用于标识该图像在系统中的位置
    uint8_t type;          // 图像类型,用于指示该图像的具体格式或用途(例如位图、编码图像等)
    uint8_t flags;         // 图像的标志位,通常用于表示图像的特定属性(例如是否是透明图像等)
    uint32_t width;        // 图像的宽度,以像素为单位
    uint32_t height;       // 图像的高度,以像素为单位
};
cpp 复制代码
struct qxl_encoder_data {
    uint32_t data_size;   // 编码数据的大小,单位是字节。
    uint8_t data[];       // 可变长度的编码数据,存储编码后的图像或图形数据。
};
cpp 复制代码
struct qxl_palette {
    uint64_t unique;      // 唯一标识符,用于区分不同的调色板。每个调色板都会有一个唯一的 ID。
    uint16_t num_ents;    // 调色板条目的数量,即调色板中包含的颜色数。
    uint32_t ents[];      // 可变长度数组,存储调色板中的颜色值。每个条目代表一个颜色,通常是32位颜色值(例如 RGBA)。
};
cpp 复制代码
struct qxl_bitmap {
    uint8_t format;        // 位图的格式,表示图像数据的颜色深度或编码方式。
    uint8_t flags;         // 位图的标志字段,指示位图的附加属性或状态。
    uint32_t x;            // 位图的 X 坐标,表示位图左上角的位置。
    uint32_t y;            // 位图的 Y 坐标,表示位图左上角的位置。
    uint32_t stride;       // 位图每行的字节数,即图像数据的跨度。用于访问像素数据时的步长。
    QXLPHYSICAL palette;   // 调色板的物理地址,用于与调色板相关的数据。通常这是指向 `qxl_palette` 结构体的指针。
    QXLPHYSICAL data;      // 图像数据的物理地址。指向存储位图像素数据的内存区域。
};
cpp 复制代码
struct qxl_surface {
    uint32_t format;      // 图形表面的格式(例如 RGBA,BGRA 等)
    uint32_t width;       // 表面的宽度
    uint32_t height;      // 表面的高度
    int32_t stride;       // 行跨度,表示表面每行数据占用的字节数
    QXLPHYSICAL data;     // 指向表面数据的物理地址
};
cpp 复制代码
struct qxl_surface_cmd {
    union qxl_release_info release_info;  // 用于释放的额外信息
    uint32_t surface_id;                  // 表面ID,标识一个具体的图形表面
    uint8_t type;                         // 命令类型,指示是创建表面还是销毁表面
    uint32_t flags;                       // 命令标志,可能用于控制命令的行为
    union {
        struct qxl_surface surface_create;  // 创建表面时的相关信息
    } u;
};
cpp 复制代码
struct qxl_clip_rects {
    uint32_t num_rects;       // 包含的矩形数量
    struct qxl_data_chunk chunk;  // 包含矩形数据的内容
};
cpp 复制代码
struct qxl_drawable {
    // 释放信息,用于释放渲染资源时的管理
    union qxl_release_info release_info;

    // 该可绘制对象使用的表面ID
    uint32_t surface_id;

    // 绘制效果类型,用于标识渲染操作的效果类型(例如:透明、混合等)
    uint8_t effect;

    // 绘制对象类型,定义该对象的类型(例如:填充、文本、复制等)
    uint8_t type;

    // 标记是否是自带位图数据,如果是,则会直接使用该位图
    uint8_t self_bitmap;

    // 如果是自带位图,定义位图的有效区域
    struct qxl_rect self_bitmap_area;

    // 可绘制对象的边界框,定义了渲染的边界范围
    struct qxl_rect bbox;

    // 裁剪区域,定义了在渲染时应考虑的区域,超出该区域的部分将被裁剪掉
    struct qxl_clip clip;

    // 内存管理时间戳,用于标识该对象的渲染时间
    uint32_t mm_time;

    // 目标表面数组,最多支持三个目标表面
    int32_t surfaces_dest[3];

    // 每个目标表面的渲染区域矩形
    struct qxl_rect surfaces_rects[3];

    // 根据绘制类型选择不同的绘制操作,这里使用联合体来支持多种操作
    union {
        // 填充操作,例如使用颜色填充区域
        struct qxl_fill fill;
        
        // 不透明操作,可能表示不透明的填充区域
        struct qxl_opaque opaque;
        
        // 复制操作,将源区域复制到目标区域
        struct qxl_copy copy;
        
        // 透明操作,可能表示透明背景或区域
        struct qxl_transparent transparent;
        
        // alpha混合操作,支持透明度的混合效果
        struct qxl_alpha_blend alpha_blend;
        
        // 复制位图操作,支持特定的位图复制
        struct qxl_copy_bits copy_bits;
        
        // 复制操作的另一种形式
        struct qxl_copy blend;
        
        // 3元逻辑操作,用于图像处理中基于位的像素操作
        struct qxl_rop_3 rop3;
        
        // 描边操作,用于绘制路径的边框
        struct qxl_stroke stroke;
        
        // 文本渲染操作,用于绘制文本
        struct qxl_text text;
        
        // 黑色掩码操作,支持黑色掩码效果
        struct qxl_mask blackness;
        
        // 反转掩码操作,用于像素的反色效果
        struct qxl_mask invers;
        
        // 白色掩码操作,支持白色掩码效果
        struct qxl_mask whiteness;
        
        // 合成操作,用于合成多个图像层
        struct qxl_composite composite;
    } u;
};
cpp 复制代码
struct qxl_cursor_header {
    uint64_t unique;          // 唯一标识符,标识一个光标
    uint16_t type;            // 光标类型(例如:标准光标、自定义光标)
    uint16_t width;           // 光标的宽度(以像素为单位)
    uint16_t height;          // 光标的高度(以像素为单位)
    uint16_t hot_spot_x;      // 热点位置的 X 坐标(相对于光标左上角)
    uint16_t hot_spot_y;      // 热点位置的 Y 坐标(相对于光标左上角)
};
cpp 复制代码
struct qxl_cursor {
    struct qxl_cursor_header header;  // 光标的基本信息
    uint32_t data_size;              // 光标数据的大小
    struct qxl_data_chunk chunk;     // 包含光标数据的内容(例如:像素数据)
};
cpp 复制代码
struct qxl_cursor_cmd {
    union qxl_release_info release_info;  // 释放信息,用于同步或更新
    uint8_t type;                         // 光标操作类型(例如:设置、移动、隐藏)
    union {
        struct {  
            struct qxl_point_1_6 position;   // 光标的新位置
            uint8_t visible;                 // 光标是否可见
            QXLPHYSICAL shape;               // 光标形状数据
        } set;                              // 设置光标操作
        struct {  
            uint16_t length;                 // 光标轨迹的长度
            uint16_t frequency;              // 光标轨迹的频率
        } trail;                            // 设置光标轨迹操作
        struct qxl_point_1_6 position;      // 光标的新位置(在移动或其他命令中使用)
    } u;
    uint8_t device_data[QXL_CURSOR_DEVICE_DATA_SIZE];  // 设备特定数据,大小为 128 字节
};
cpp 复制代码
struct qxl_ram_header {
    uint32_t magic;                            // 魔术数字,用于验证数据结构是否正确
    uint32_t int_pending;                      // 当前挂起的中断
    uint32_t int_mask;                         // 中断屏蔽
    uint8_t log_buf[QXL_LOG_BUF_SIZE];         // 日志缓冲区,用于记录日志
    struct qxl_ring_header cmd_ring_hdr;       // 命令环头,用于管理命令队列
    struct qxl_command cmd_ring[QXL_COMMAND_RING_SIZE]; // 命令环,用于存储具体的命令
    struct qxl_ring_header cursor_ring_hdr;    // 光标环头,用于管理光标队列
    struct qxl_command cursor_ring[QXL_CURSOR_RING_SIZE]; // 光标环,用于存储光标命令
    struct qxl_ring_header release_ring_hdr;   // 释放环头,用于管理释放命令
    uint64_t release_ring[QXL_RELEASE_RING_SIZE]; // 释放环,用于存储释放命令
    struct qxl_rect update_area;               // 更新区域,表示图形更新的区域
    /* appended for qxl-2 */
    uint32_t update_surface;                   // 更新的表面 ID,用于指定目标表面
    struct qxl_mem_slot mem_slot;              // 内存槽,用于分配图形内存
    struct qxl_surface_create create_surface;  // 表面创建结构,表示新创建的图形表面
    uint64_t flags;                            // 标志位,用于存储相关的配置信息

    /* appended for qxl-4 */
    /* used by QXL_IO_MONITORS_CONFIG_ASYNC */
    QXLPHYSICAL monitors_config;               // 显示器配置,用于存储显示器相关的配置信息
    uint8_t guest_capabilities[64];            // 客户端能力,存储与虚拟机环境相关的信息
};
cpp 复制代码
/* qxl-1 compat: append only */
struct qxl_rom {
    uint32_t magic;                         // 魔术数,用于验证这是一个有效的 QXL ROM
    uint32_t id;                            // ROM 的唯一标识符
    uint32_t update_id;                     // 更新标识符,用于标记 ROM 版本或更新次数
    uint32_t compression_level;             // 压缩级别,可能指示 ROM 数据的压缩程度
    uint32_t log_level;                     // 日志级别,控制 QXL 驱动的日志输出详细程度
    uint32_t mode;                          // 驱动的工作模式(qxl-1 特定)
    uint32_t modes_offset;                  // 显示模式的偏移量,指向模式数据的位置
    uint32_t num_io_pages;                  // I/O 页的数量,表示 ROM 中的 I/O 页数量
    uint32_t pages_offset;                  // 页面的偏移量,指向页面数据的位置(qxl-1 特定)
    uint32_t draw_area_offset;              // 绘制区域的偏移量,表示绘制区域在 ROM 中的位置(qxl-1 特定)
    uint32_t surface0_area_size;            // 表面0区域的大小,用于描述第一个图形表面的内存大小(qxl-1 特定,名为 draw_area_size)
    uint32_t ram_header_offset;             // RAM 头部的偏移量,指向 RAM 头部数据的位置
    uint32_t mm_clock;                      // 内存时钟频率,控制 RAM 访问的时序,影响性能

    /* qxl-2 特有字段 */
    uint32_t n_surfaces;                   // 表面数量,表示支持的图形表面数量
    uint64_t flags;                         // 标志位,存储驱动的配置特性
    uint8_t slots_start;                    // 起始槽位,内存槽位的起始位置
    uint8_t slots_end;                      // 结束槽位,内存槽位的结束位置
    uint8_t slot_gen_bits;                  // 槽生成位数,用于标识槽位的生成位
    uint8_t slot_id_bits;                   // 槽 ID 位数,表示槽位的唯一标识符的位数
    uint8_t slot_generation;                // 槽代号,用于表示槽位的代次(内存管理、版本控制)

    /* qxl-4 特有字段 */
    uint8_t client_present;                 // 客户端存在标志,指示客户端是否存在
    uint8_t client_capabilities[58];        // 客户端的能力位图,描述客户端支持的功能或特性
    uint32_t client_monitors_config_crc;    // 客户端显示配置的 CRC 校验和,用于验证配置的有效性
    struct {
        uint16_t count;                     // 显示器配置的数量
        uint16_t padding;                   // 填充,保持对齐
        struct qxl_urect heads[64];         // 显示器配置,最多支持 64 个显示器
    } client_monitors_config;               // 客户端监视器配置,描述显示器的位置和尺寸
};
相关推荐
cxr8284 天前
SPARC方法论在Claude Code基于规则驱动开发中的应用
人工智能·驱动开发·claude·智能体
sukalot4 天前
window显示驱动开发—显示适配器的子设备
驱动开发
Evan_ZGYF丶5 天前
【RK3576】【Android14】如何在Android14下单独编译kernel-6.1?
linux·驱动开发·android14·rk3576
sukalot6 天前
window显示驱动开发—视频呈现网络简介
驱动开发
sukalot6 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)
驱动开发
zwhSunday6 天前
Linux驱动开发(1)概念、环境与代码框架
linux·运维·驱动开发
sukalot7 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(三)
驱动开发
sukalot7 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(一)
驱动开发
cxr8288 天前
基于Claude Code的 规范驱动开发(SDD)指南
人工智能·hive·驱动开发·敏捷流程·智能体
zwhSunday8 天前
Linux驱动开发(2)进一步理解驱动
linux·驱动开发