uefi_3

GraphicsOutPutProtocol图形输出协议

GraphicsOutPutProtocol作为学习的第一个协议,它的头文件位于MdePkg/Include/Protocol/GraphicsOutput.h,Guid如下:

1
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }};

除去最后一个PixelFormatMax用于范围检查,GraphicsOutPut总计提供了4种可选格式,小端存储下使用32位扩展RGB888格式的应该选择第二个PixelBlueGreenRedReserved8BitPerColor,而使用24位RGB888、16位RGB565、RGB555或其他格式的则应该选择第三个PixelBitMask,这点需要注意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct {
UINT32 RedMask;
UINT32 GreenMask;
UINT32 BlueMask;
UINT32 ReservedMask;
} EFI_PIXEL_BITMASK;
typedef enum {
// PhysicalFrameBuffer的RGBA格式,字节0-2分别为红绿蓝,字节3保留。
PixelRedGreenBlueReserved8BitPerColor,
// PhysicalFrameBuffer的BGRA格式,字节0-2分别为蓝绿红,字节3保留。
PixelBlueGreenRedReserved8BitPerColor,
// PhysicalFrameBuffer的BitMask格式,需要EFI_PIXEL_BITMASK确定各颜色位置
PixelBitMask,
// 不支持PhysicalFrameBuffer意味着无法直接通过物理内存地址写入,仅支持Blt操作
PixelBltOnly,
// 格式范围检查
PixelFormatMax
} EFI_GRAPHICS_PIXEL_FORMAT;

对比传统BIOS下VESA的定义(不了解VESA的需要重点看下面内容),X对应Width,Y对应Height,像素格式对应BPP(Bits Per Pixel),每行像素数量对应Pitch(Bytes Per Scanline)。

不使用Blt直接操作FrameBuffer时需要注意,Pitch并不一定等于Width,因为各种原因(比如内存对齐,像素格式等),像素数据不一定是连续的,像素行与像素行之间可能存在填充(Padding),所以在计算第Y行,第X列像素的偏移时,计算公式应该是:Offset =(Y * Pitch + X)* BPP,禁止将Pitch替换为Width避免出现花屏等问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct {
// 版本号固定放在开头,值为0代表当前的EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
UINT32 Version;
// 视频屏幕的水平方向X的像素尺寸
UINT32 HorizontalResolution;
// 视频屏幕的垂直方向Y的像素尺寸
UINT32 VerticalResolution;
// 像素格式
EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
// 仅像素格式为BitMask此位有效,置位的bit定义了哪些位是红、绿、蓝或保留。
EFI_PIXEL_BITMASK PixelInformation;
// 定义视频屏幕每行包含的像素单元数量
UINT32 PixelsPerScanLine;
} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION;

过段时间再写:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 返回图形设备和当前视频输出设备组合所支持的可用图形模式信息
typedef
EFI_STATUS // 发生硬件错误返回EFI_DEVICE_ERROR,模式编号无效(超出范围)返回EFI_INVALID_PARAMETER
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, // 第一个参数必须是EFI_GRAPHICS_OUTPUT_PROTOCOL指针模拟This指针
IN UINT32 ModeNumber, // 要查询的模式编号
OUT UINTN *SizeOfInfo, // 指向缓冲区大小的指针
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info // 指向Info缓冲区大小的指针,注意它由驱动程序使用AllocatePool()分配内存,完成调用后,必须使用FreePool()释放内存避免内存泄漏
);
// 将视频设备设置为指定模式,并将屏幕可见区域清空为黑色
typedef
EFI_STATUS // 发生硬件错误返回EFI_DEVICE_ERROR,不支持此模式编号返回EFI_UNSUPPORTED
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, // This指针
IN UINT32 ModeNumber // 目标视频模式的编号
);
// 在图形屏幕上Blt一个像素矩形,Blt表示块传输(Block Transfer)
typedef
EFI_STATUS // 发生硬件错误返回EFI_DEVICE_ERROR,BltOperation参数无效返回EFI_INVALID_PARAMETER
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT)(
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, // This指针
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, // 要传输到屏幕的数据缓冲区,要求大小至少要Width * Heigth * BPP
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, // 执行复制操作的具体类型
IN UINTN SourceX, // 源X坐标
IN UINTN SourceY, // 源Y坐标
IN UINTN DestinationX, // 目的X坐标
IN UINTN DestinationY, // 目的Y坐标
IN UINTN Width, // 矩形的宽度
IN UINTN Height, // 矩形的高度
IN UINTN Delta OPTIONAL // 对于EfiBltVideoFill或EfiBltVideoToVideo无效,如果Delta为0,表示操作整个BltBuffer,如果使用的是BltBuffer的子矩阵,则Delta表示BltBuffer每行的字节跨度(Stride)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct {
// QueryMode()和SetMode()支持的模式数量
UINT32 MaxMode;
// 图形设备的当前模式,有效编号为0到最大-1
UINT32 Mode;
// 指向只读的EFI_GRAPHICS_OUTPUT_MODE_INFORMATION数据的指针
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
// Info结构的大小(单位为Byte)
UINTN SizeOfInfo;
// FrameBuffer基地址,偏移量0表示显示器的左上角像素
EFI_PHYSICAL_ADDRESS FrameBufferBase;
// 支持当前模式所需的帧缓冲区大小,由PixelsPerScanLine * VerticalResolution * PixelElementSize定义
UINTN FrameBufferSize;
} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;
typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL;
// 提供抽象层,用于设置视频模式以及在图形控制器的帧缓冲区之间复制像素
struct _EFI_GRAPHICS_OUTPUT_PROTOCOL {
EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode;
EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode;
EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt;
// 指向EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE数据的指针
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
};