video modes
[efitest1] / test.c
1 #include <efi.h>
2 #include <efilib.h>
3 #include <efiprot.h>
4
5 int find_best_video_mode(void);
6 int find_video_mode(int xres, int yres, int bpp);
7 int set_video_mode(int mode);
8 int cur_video_mode(void);
9 void draw_box(int x, int y, int w, int h, int r, int g, int b);
10 int mask_to_shift(unsigned int mask);
11 int mask_to_bpp(unsigned int mask);
12 int mode_bpp(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *minf);
13
14 uint32_t *fb;
15 int fb_width, fb_height;
16 int scanwidth;
17 int rshift, bshift, gshift;
18 unsigned int rmask, bmask, gmask;
19 EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
20
21 EFI_STATUS EFIAPI efi_main(EFI_HANDLE img, EFI_SYSTEM_TABLE *systab)
22 {
23         int mode;
24         EFI_HANDLE *handles;
25         unsigned long nhandles = 0;
26         unsigned long misize;
27         EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mi;
28         SIMPLE_TEXT_OUTPUT_INTERFACE *sout;
29
30         InitializeLib(img, systab);
31
32         sout = systab->ConOut;
33         uefi_call_wrapper(sout->ClearScreen, 1, sout);
34         Print(L"hello world\n");
35
36         LibLocateHandle(ByProtocol, &GraphicsOutputProtocol, 0, &nhandles, 0);
37         if(nhandles <= 0) {
38                 Print(L"Failed to locate any graphics output devices\n");
39                 goto end;
40         }
41         if(!(handles = AllocatePool(nhandles))) {
42                 Print(L"Failed to allocate memory for %lu handles\n", nhandles);
43                 goto end;
44         }
45         Print(L"Found %lu graphics output devices\n", nhandles);
46         if(LibLocateHandle(ByProtocol, &GraphicsOutputProtocol, 0, &nhandles, &handles) != 0) {
47                 Print(L"Failed to retreive graphics output device handles\n");
48                 goto end;
49         }
50         if(uefi_call_wrapper(BS->HandleProtocol, 3, handles[0], &GraphicsOutputProtocol, &gop) != 0) {
51                 Print(L"Failed to retreive graphics output protocol structure\n");
52                 goto end;
53         }
54
55
56         if((mode = find_best_video_mode()) == -1) {
57                 Print(L"Failed to find best video mode, leaving as is\n");
58         } else {
59                 if(set_video_mode(mode) == -1) {
60                         Print(L"Failed to change video mode, leaving as is\n");
61                 }
62         }
63         uefi_call_wrapper(gop->QueryMode, 4, gop, gop->Mode->Mode, &misize, &mi);
64
65         fb_width = mi->HorizontalResolution;
66         fb_height = mi->VerticalResolution;
67         scanwidth = mi->PixelsPerScanLine;
68
69         switch(mi->PixelFormat) {
70         case PixelRedGreenBlueReserved8BitPerColor:
71                 rshift = 0;
72                 gshift = 8;
73                 bshift = 16;
74                 rmask = 0xff;
75                 gmask = 0xff00;
76                 bmask = 0xff0000;
77                 break;
78
79         case PixelBlueGreenRedReserved8BitPerColor:
80                 rshift = 16;
81                 gshift = 8;
82                 bshift = 0;
83                 rmask = 0xff0000;
84                 gmask = 0xff00;
85                 bmask = 0xff;
86                 break;
87
88         case PixelBitMask:
89                 rmask = mi->PixelInformation.RedMask;
90                 gmask = mi->PixelInformation.GreenMask;
91                 bmask = mi->PixelInformation.BlueMask;
92                 rshift = mask_to_shift(rmask);
93                 gshift = mask_to_shift(gmask);
94                 bshift = mask_to_shift(bmask);
95                 break;
96
97         default:
98                 Print(L"Unsupported pixel format\n");
99                 goto end;
100         }
101         fb = (uint32_t*)gop->Mode->FrameBufferBase;
102
103         Print(L"Video mode %ux%u %dbpp (fmt id: %u)\n", mi->HorizontalResolution,
104                         mi->VerticalResolution, mask_to_bpp(rmask | gmask | bmask), (unsigned int)mi->PixelFormat);
105
106         draw_box(100, 100, 200, 200, 255, 128, 64);
107
108 end:
109         asm volatile("cli");
110         for(;;) {
111                 asm volatile("hlt");
112         }
113
114         return EFI_SUCCESS;
115 }
116
117 static uint32_t calc_score(int x, int y, int bpp)
118 {
119         uint32_t a = y >> 5;
120         uint32_t b = x >> 5;
121
122         if(a > 0xfff) a = 0xfff;
123         if(b > 0xfff) b = 0xfff;
124
125         return (a << 20) | (b << 8) | (bpp & 0xff);
126 }
127
128 int find_best_video_mode(void)
129 {
130         int i, nmodes, w, h;
131         int score, best_score = 0, best_mode = -1;
132         unsigned long misize;
133         EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mi;
134
135         nmodes = gop->Mode->MaxMode;
136         for(i=0; i<nmodes; i++) {
137                 uefi_call_wrapper(gop->QueryMode, 4, gop, i, &misize, &mi);
138                 w = mi->HorizontalResolution;
139                 h = mi->VerticalResolution;
140
141                 score = calc_score(w, h, mode_bpp(mi));
142                 if(score > best_score) {
143                         best_score = score;
144                         best_mode = i;
145                 }
146         }
147         return best_mode;
148 }
149
150 int find_video_mode(int xres, int yres, int bpp)
151 {
152         int i, nmodes, w, h;
153         unsigned long misize;
154         EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mi;
155
156         nmodes = gop->Mode->MaxMode;
157         for(i=0; i<nmodes; i++) {
158                 uefi_call_wrapper(gop->QueryMode, 4, gop, i, &misize, &mi);
159                 w = mi->HorizontalResolution;
160                 h = mi->VerticalResolution;
161                 if(w == xres && h == yres && mode_bpp(mi) >= bpp) {
162                         return i;
163                 }
164         }
165         return -1;
166 }
167
168 int set_video_mode(int mode)
169 {
170         if(uefi_call_wrapper(gop->SetMode, 2, gop, mode) != 0) {
171                 return -1;
172         }
173         return 0;
174 }
175
176 int cur_video_mode(void)
177 {
178         return gop->Mode->Mode;
179 }
180
181 void draw_box(int x, int y, int w, int h, int r, int g, int b)
182 {
183         int i, j;
184         uint32_t pixcol;
185         uint32_t *pptr = fb + y * scanwidth + x;
186
187         pixcol = (((uint32_t)r << rshift) & rmask) |
188                 (((uint32_t)g << gshift) & gmask) |
189                 (((uint32_t)b << bshift) & bmask);
190
191         for(i=0; i<h; i++) {
192                 for(j=0; j<w; j++) {
193                         *pptr++ = pixcol;
194                 }
195                 pptr += scanwidth - w;
196         }
197 }
198
199 int mask_to_shift(unsigned int mask)
200 {
201         int res = 0;
202         while((mask & 1) == 0) {
203                 mask >>= 1;
204                 res++;
205         }
206         return res;
207 }
208
209 int mask_to_bpp(unsigned int mask)
210 {
211         int res = 0;
212
213         while(mask) {
214                 mask >>= 1;
215                 res++;
216         }
217         return res;
218 }
219
220 int mode_bpp(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *minf)
221 {
222         switch(minf->PixelFormat) {
223         case PixelRedGreenBlueReserved8BitPerColor:
224         case PixelBlueGreenRedReserved8BitPerColor:
225                 return 24;
226
227         case PixelBitMask:
228                 return mask_to_bpp(minf->PixelInformation.RedMask | minf->PixelInformation.GreenMask |
229                                 minf->PixelInformation.BlueMask);
230
231         default:
232                 break;
233         }
234         return 0;
235 }