-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscreen.c
149 lines (128 loc) · 3.51 KB
/
screen.c
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "screen.h"
const bgr WHITE = BGR(255, 255, 255);
const bgr RED = BGR(0, 0, 255);
const bgr BLUE = BGR(255, 0, 0);
const bgr GREEN = BGR(0, 255, 0);
const bgr BLACK = BGR(0, 0, 0);
void fill_rect(LFB * const lfb, rect rect, bgr color) {
// Print(
// L"DEBUG: fill_rect at %d,%d+%dx%d\n",
// rect.x,
// rect.y,
// rect.w,
// rect.h);
UINT32 x0 = rect.x, y0 = rect.y;
for(UINT32 x = x0; x < x0 + rect.w; x++) {
for(UINT32 y = y0; y < y0 + rect.h; y++) {
SET_BUFFER_PIXEL(lfb, x, y, color);
}
}
}
void screen_buffer_clear(LFB * const lfb, bgr color) {
Print(L"DEBUG: cleared screen buffer.\n");
for(int i = 0; i < lfb->width * lfb->height; i++) {
lfb->buffer[i] = color;
}
}
void screen_buffer_copy(LFB * const lfb) {
for(int i = 0; i < lfb->width * lfb->height; i++) {
lfb->pixels[i] = lfb->buffer[i];
}
}
#if MOCK_LFB
/**
* \brief
* Static space to use for the mock video memory.
*/
static mock_vram_t mock_vram = {};
/**
* \brief
* Loads an LFB that just does draws into memory and doesn't set the
* video mode.
* This can be used for debugging, as Print and so on will still work.
*/
LFB
load_lfb(EFI_STATUS * status) {
*status = EFI_SUCCESS;
return (LFB) {
.pixels = mock_vram.data,
.buffer = SCREEN_BUFFER.data,
.width = SCREEN_WIDTH,
.height = SCREEN_HEIGHT,
.pixels_per_scanline = 1
};
}
#else
// real graphics mode setup
/**
* \brief
* Decide whether a given graphics mode has the required resolution.
*/
static int
mode_is_suitable(
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION const * const info) {
//
UINTN h = info->VerticalResolution;
UINTN w = info->HorizontalResolution;
Print(L"Trying %dx%d\n", w, h);
return w == SCREEN_WIDTH && h == SCREEN_HEIGHT &&
info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor;
}
/**
* \brief
* Enumerates video modes until one satisfying `mode_is_suitable` is
* found, and sets the active mode to that mode.
*/
static EFI_STATUS
find_and_set_video_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL * const gop) {
EFI_STATUS status;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN info_size;
// enumerate available video modes
for(int mode_i = 0; mode_i < gop->Mode->MaxMode; mode_i++) {
if(EFI_ERROR(
(status =
gop->QueryMode(gop, mode_i, &info_size, &info))))
return status;
if(!mode_is_suitable(info)) {
continue;
}
return gop->SetMode(gop, mode_i);
}
return EFI_NOT_FOUND;
}
/**
* \brief
* Prepares the linear frame buffer by finding the GOP and setting the
* video mode.
*
* Unconditionally sets *_status. The return value is undefined if
* EFI_ERROR(*_status) is true.
*/
LFB
load_lfb(EFI_STATUS * status) {
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
if(EFI_ERROR(
(*status =
ST->BootServices->LocateProtocol(
&gop_guid,
NULL,
(void**)&gop)))) {
Print(L"FATAL: failed to locate GOP.\n");
return (LFB) {};
}
Print(L"Framebuffer base is at %lx\n", gop->Mode->FrameBufferBase);
Print(L"Finding a suitable video mode; preferred resolution: 640x480.\n");
if(EFI_ERROR((*status = find_and_set_video_mode(gop))))
return (LFB) {};
*status = EFI_SUCCESS;
return (LFB) {
.pixels = (bgr*) gop->Mode->FrameBufferBase,
.buffer = SCREEN_BUFFER.data,
.width = gop->Mode->Info->HorizontalResolution,
.height = gop->Mode->Info->VerticalResolution,
.pixels_per_scanline = gop->Mode->Info->PixelsPerScanLine
};
}
#endif