驅動開發系列57 - Linux Graphics QXL顯卡驅動代碼分析(四)顯示區域更新

一:概述

? ? ? ? 前面在介紹了顯示模式設置(分辨率,刷新率)之后,本文繼續分析下,顯示區域的繪制,詳細看看虛擬機的畫面是如何由QXL顯卡繪制出來的。?

二:相關數據結構介紹?

struct qxl_monitors_config {uint16_t count;         // 當前啟用的顯示器數量(head 數量)uint16_t max_allowed;   // 驅動允許的最大顯示器數量,如果為 0,表示沒有固定限制,由驅動動態決定struct qxl_head heads[]; // 每個顯示器的配置數組(實際大小為 count)
};
struct qxl_head {uint32_t id;           // 顯示頭(顯示器)IDuint32_t surface_id;   // 綁定的 QXLSurface IDuint32_t width;        // 顯示區域的寬度(像素)uint32_t height;       // 顯示區域的高度(像素)uint32_t x;            // 在綁定 surface 上的 X 偏移(起始坐標)uint32_t y;            // 在綁定 surface 上的 Y 偏移uint32_t flags;        // 標志位,用于額外配置(比如是否啟用、旋轉等)
};
struct qxl_surface_id {uint32_t surface_id; // 表示 QXL 表面(Surface)的唯一標識符。每個表面都會有一個唯一的 ID,用于區分和識別不同的表面。
};
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;
};
struct qxl_image_descriptor {uint64_t id;           // 圖像的唯一標識符,用于標識該圖像在系統中的位置uint8_t type;          // 圖像類型,用于指示該圖像的具體格式或用途(例如位圖、編碼圖像等)uint8_t flags;         // 圖像的標志位,通常用于表示圖像的特定屬性(例如是否是透明圖像等)uint32_t width;        // 圖像的寬度,以像素為單位uint32_t height;       // 圖像的高度,以像素為單位
};
struct qxl_encoder_data {uint32_t data_size;   // 編碼數據的大小,單位是字節。uint8_t data[];       // 可變長度的編碼數據,存儲編碼后的圖像或圖形數據。
};
struct qxl_palette {uint64_t unique;      // 唯一標識符,用于區分不同的調色板。每個調色板都會有一個唯一的 ID。uint16_t num_ents;    // 調色板條目的數量,即調色板中包含的顏色數。uint32_t ents[];      // 可變長度數組,存儲調色板中的顏色值。每個條目代表一個顏色,通常是32位顏色值(例如 RGBA)。
};
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;      // 圖像數據的物理地址。指向存儲位圖像素數據的內存區域。
};
struct qxl_surface {uint32_t format;      // 圖形表面的格式(例如 RGBA,BGRA 等)uint32_t width;       // 表面的寬度uint32_t height;      // 表面的高度int32_t stride;       // 行跨度,表示表面每行數據占用的字節數QXLPHYSICAL data;     // 指向表面數據的物理地址
};
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;
};
struct qxl_clip_rects {uint32_t num_rects;       // 包含的矩形數量struct qxl_data_chunk chunk;  // 包含矩形數據的內容
};
struct qxl_drawable {// 釋放信息,用于釋放渲染資源時的管理union qxl_release_info release_info;// 該可繪制對象使用的表面IDuint32_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;
};
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 坐標(相對于光標左上角)
};
struct qxl_cursor {struct qxl_cursor_header header;  // 光標的基本信息uint32_t data_size;              // 光標數據的大小struct qxl_data_chunk chunk;     // 包含光標數據的內容(例如:像素數據)
};
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 字節
};
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];            // 客戶端能力,存儲與虛擬機環境相關的信息
};
/* qxl-1 compat: append only */
struct qxl_rom {uint32_t magic;                         // 魔術數,用于驗證這是一個有效的 QXL ROMuint32_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;               // 客戶端監視器配置,描述顯示器的位置和尺寸
};

三:顯示區域更新介紹

? ? ? ? 下面這段代碼是用戶空間通過 ioctl 發來的更新顯示區域命令,這個代碼的主要邏輯如下:

? ? ? ? 1. 首先解析用戶空間輸入的更新區域,并檢查區域是否有效。

? ? ? ? 2. 然后根據用戶空間傳遞的GEM對象句柄,查找到顯存中的緩沖區對象。

? ? ? ? 3. 將緩沖區對象固定在顯存中,并映射到內核虛擬空間,加鎖。

? ? ? ? 4. 調用 qxl_io_update_area 更新指定的區域,這個函數的意思是給QXL 顯卡發送命令,并等待命令完成。

? ? ? ? 5. 更新完成后,解鎖,釋放相關資源。


int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf,const struct qxl_rect *area)
{int surface_id;uint32_t surface_width, surface_height;int ret;if (!surf->hw_surf_alloc)DRM_ERROR("got io update area with no hw surface\n");if (surf->is_primary)surface_id = 0;elsesurface_id = surf->surface_id;surface_width = surf->surf.width;surface_height = surf->surf.height;if (area->left < 0 || area->top < 0 ||area->right > surface_width || area->bottom > surface_height)return -EINVAL;mutex_lock(&qdev->update_area_mutex);qdev->ram_header->update_area = *area;qdev->ram_header->update_surface = surface_id;ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true);mutex_unlock(&qdev->update_area_mutex);return ret;
}

四:dma_fence 介紹

? ? ? ? dma_fence 是 Linux 內核中用于同步GPU 或其他設備訪問共享內存(如 buffer object)的機制。 比如 CPU 將渲染任務交給GPU(命令提交),GPU可能幾毫秒后完成,所以此時就會建一個fence,意思是說別動這塊內存,GPU正在使用,等GPU完成后,這個“牌子”就會被撤掉,CPU就可以安全訪問了。

? ? ? ? 在qxl驅動中,qxl_release 表示一次命令提交,當用戶空間在命令提交時,qxl的?qxl_release_fence_buffer_objects 就會將一個buffer object 關聯上一個dma_fence, 這樣命令執行完成時,可以設置dma_fence 狀態,用于通知用戶空間了;下面是dma_fence 函數介紹和一個流程圖:

????????

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79224.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79224.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79224.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

遠程調用負載均衡LoadBalancer

1. 什么是負載均衡 負載均衡就是將負載&#xff08;工作任務&#xff0c;訪問請求&#xff09;進行分攤到多個操作單元&#xff08;服務器,組件&#xff09;上進行執行。 根據負載均衡發生位置的不同,一般分為服務端負載均衡和客戶端負載均衡。 服務端負載均衡&#xff1a;指的…

【深度學習】【目標檢測】【Ultralytics-YOLO系列】YOLOV3核心文件detect.py解讀

【深度學習】【目標檢測】【Ultralytics-YOLO系列】YOLOV3核心文件detect.py解讀 文章目錄 【深度學習】【目標檢測】【Ultralytics-YOLO系列】YOLOV3核心文件detect.py解讀前言if name ‘main’parse_opt函數main函數run函數不同命令參數的推理結果常規推理命令推理命令(新增…

NextPolish1.4.1 安裝與使用-bioinformatics tools54

01 簡介 NextPolish 是一個用于修正由低準確度長讀段&#xff08;如 ONT 或 CLR&#xff09;組裝出來的基因組序列中堿基錯誤&#xff08;SNV/Indel&#xff09;的工具。它支持&#xff1a; 僅使用短讀段 僅使用長讀段 同時使用短讀段與長讀段 NextPolish 包含兩個核心模塊…

Vue3 el-tree:全選時只返回父節點,半選只返回勾選中的節點(省-市區-縣-鎮-鄉-村-街道)

需求原因&#xff1a;全選時&#xff0c;傳給接口的code數據太多了&#xff1b; 如果加上 check-strictly 父節點與子節點無關聯&#xff0c;可以初步滿足需求 效果如下使用了check-strictly的話&#xff0c;tree就沒有了半選效果 不好的地方&#xff1a;用戶體驗感不好&#x…

使用 docker 安裝 nacos3.x

一、安裝 nacos 1.拉取鏡像 使用如下指令拉取鏡像 docker pull nacos/nacos-server 拉取完成后&#xff0c;可以使用以下命令查看是否拉取到對應的鏡像&#xff0c;默認拉取最新鏡像 docker images 2.新建掛載文件目錄 mkdir -p /home/ubuntu/nacos/conf/mkdir -p /home/…

高性能Python Web 框架--FastAPI 學習「基礎 → 進階 → 生產級」

以下是針對 FastAPI 的保姆級教程&#xff0c;包含核心概念、完整案例和關鍵注意事項&#xff0c;采用「基礎 → 進階 → 生產級」的三階段教學法&#xff1a; 一、FastAPI介紹 FastAPI 是一個現代化的、高性能的 Python Web 框架&#xff0c;專門用于構建 APIs&#xff08;應…

H2 Database Select 語句執行流程

H2 Database Select 語句執行流程 使用 // CREATE TABLE IF NOT EXISTS test(id INT primary key, name VARCHAR(255)) // insert into test(id, name) values(1, name1), (2, name2), (3, name3), (4, name4); String sql "SELECT * FROM test where id > 1 and na…

理解 Envoy 的架構

理解 Envoy 的架構對于深入理解 Istio 至關重要&#xff0c;因為 Envoy 是 Istio 數據平面的核心。Envoy 是一個高性能的 C 分布式代理&#xff0c;設計為云原生應用和大規模微服務架構的網絡基礎。 以下是 Envoy 架構的關鍵組成部分和核心理念&#xff1a; 核心設計理念&…

Android開發-常用布局

在Android應用開發中&#xff0c;布局決定了用戶界面的結構和元素之間的相對位置。選擇合適的布局不僅能夠提升用戶體驗&#xff0c;還能提高代碼的可維護性和靈活性。本文將介紹幾種最常用的Android布局方式&#xff0c;包括LinearLayout、RelativeLayout、ConstraintLayout以…

如何在MySQL中實現類似Redis的PING命令的功能來檢測連接狀態?

要在MySQL中實現類似Redis的PING命令的功能來檢測連接狀態&#xff0c;可以采用以下方法&#xff1a; 方法一&#xff1a;使用簡單的SQL查詢 最直接的方法是通過執行一個簡單的查詢來檢測連接狀態&#xff0c;例如&#xff1a; SELECT 1;如果查詢成功并返回結果&#xff08;…

Vue 系列之:defineProps、defineEmits、...

defineProps 用于接收父組件傳遞的屬性值。 父組件&#xff1a; <!-- 父組件 --> <template><Child1 str"字符串" :num"num" />-----------------<Child2 str"字符串" :num"num" /> </template><…

windows服務器部署Gitlab

代碼托管,如果對工具功能要求不高,Gitea也可以滿足需要,只是功能相對比較簡單。 通常GltLab是部署在linux服務器上的,windows版本已經不維護了。不過現在windows10 11已經可以實現部署了,一個是windows本機部署linux虛擬機(windows商店直接安裝或者其他虛擬機平臺都可以)…

剖析 FFmpeg:從基本功能到過濾器,實現音視頻處理的靈活性

目錄 1.解復用2 解碼2.1 音頻解碼2.2 視頻解碼 3 修飾3.1 avio3.2 重采樣 4 過濾器4.1 過濾器基本知識4.2 簡單過濾器4.3 復雜濾鏡圖 1.解復用 解復用就是把容器中的媒體流分離出來&#xff0c;方便我們對媒體流處理。 step1&#xff1a;對媒體文件上下文初始化 AVFormatCont…

kafka學習筆記(四、生產者、消費者(客戶端)深入研究(三)——事務詳解及代碼實例)

1.事務簡介 Kafka事務是Apache Kafka在流處理場景中實現Exactly-Once語義的核心機制。它允許生產者在跨多個分區和主題的操作中&#xff0c;以原子性&#xff08;Atomicity&#xff09;的方式提交或回滾消息&#xff0c;確保數據處理的最終一致性。例如&#xff0c;在流處理中…

Missashe計網復習筆記(隨時更新)

Missashe計算機網絡復習筆記 前言&#xff1a;這篇筆記用于博主對計網這門課所學進行記錄和總結&#xff0c;也包括一些個人的理解。正在更新當中…… 第一章 計算機網絡體系結構 考綱內容 (一) 計算機網絡概述 計算機網絡的概念、組成與功能;計算機網絡的分類; 計算機網絡…

PVP鼠標推薦(deepseek)

下面有不懂的自行百度查找&#x1f44d; ?? 以下是幾款在 雙擊性能&#xff08;DBC&#xff09; 和 拖拽點擊&#xff08;DC&#xff09; 方面表現優秀的游戲鼠標推薦&#xff0c;結合了硬件性能、微動壽命以及玩家口碑&#xff1a; 1. 羅技 G102/G203 Lightsync 特點&#…

ABP vNext + EF Core 實戰性能調優指南

ABP vNext EF Core 實戰性能調優指南 &#x1f680; 目標 本文面向中大型 ABP vNext 項目&#xff0c;圍繞查詢性能、事務隔離、批量操作、緩存與診斷&#xff0c;系統性地給出優化策略和最佳實踐&#xff0c;幫助讀者快速定位性能瓶頸并落地改進。 &#x1f4d1; 目錄 ABP vN…

為啥大模型一般將kv進行緩存,而q不需要

1. 自回歸生成的特點 大模型&#xff08;如 GPT 等&#xff09;在推理時通常采用自回歸生成的方式&#xff1a; 模型逐個生成 token&#xff0c;每次生成一個新 token 時&#xff0c;需要重新計算注意力。在生成第 t 個 token 時&#xff0c;模型需要基于前 t-1 個已生成的 t…

3DGS-slam:splatam公式

配套講解視頻&#xff1a;https://www.bilibili.com/video/BV1ZgfBYdEpg/?spm_id_from333.1387.homepage.video_card.click&vd_sourced4c3e747c32049ddd90dcce17208f4e0 1、多維高斯分布公式: 對于多維&#xff08;多變量&#xff09;高斯分布&#xff0c;概率密度函數的…

從Dockerfile 構建docker鏡像——保姆級教程

從Dockfile開始 dockerfile簡介開始構建1、編輯dockerfile2、構建鏡像3、拉取鏡像4、推送到鏡像倉庫 鏡像的優化1、優化的基本原則2、多階段構建 dockerfile簡介 開始構建 1、編輯dockerfile # 使用官方的 Python 3.8 鏡像作為基礎鏡像 FROM python:3.8-slim# 設置工作目錄 …