malloc->zalloc
[grub2/phcoder.git] / commands / videotest.c
blob54457ea0f603a6e7e2289e3263245459fb9ccfd1
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/time.h>
20 #include <grub/video.h>
21 #include <grub/types.h>
22 #include <grub/dl.h>
23 #include <grub/extcmd.h>
24 #include <grub/misc.h>
25 #include <grub/mm.h>
26 #include <grub/font.h>
27 #include <grub/term.h>
28 #include <grub/bitmap.h>
29 #include <grub/bitmap_scale.h>
31 /* Option array indices. */
32 #define ARGINDEX_TEST_TIME 0
33 #define ARGINDEX_DOUBLE_BUF 1
35 static const struct grub_arg_option arg_options[] = {
36 {"time", 't', 0, "Time to run each test, in seconds.", 0, ARG_TYPE_INT},
37 {"dbuf", 'd', 0, "Use double buffered graphics.", 0, ARG_TYPE_NONE},
38 {0, 0, 0, 0, 0, 0}
41 #define DEFAULT_TEST_TIME 5
43 /* Command options -- populated base on command line arguments. */
44 struct videotest_options
46 int test_time;
47 int double_buffering;
50 /* List of video modes to try when an exact resolution is not required. */
51 static const char preferred_mode_list[] = "1024x768;800x600;640x480";
53 static void
54 basic_video_test (struct videotest_options *vt_opts)
56 grub_video_color_t color;
57 grub_video_color_t bg;
58 unsigned int x;
59 unsigned int y;
60 unsigned int width;
61 unsigned int height;
62 int i;
63 struct grub_font_glyph *glyph;
64 struct grub_video_render_target *text_layer;
65 grub_font_t fixed;
66 grub_video_color_t palette[16];
67 int info_width;
68 int info_height;
70 if (grub_video_set_mode (preferred_mode_list, 0) != GRUB_ERR_NONE)
71 return;
72 grub_video_enable_double_buffering (vt_opts->double_buffering);
74 if (! (fixed = grub_font_get ("Fixed Regular 20")))
76 grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
77 return;
80 grub_video_get_viewport (&x, &y, &width, &height);
82 grub_video_create_render_target (&text_layer, width, height,
83 GRUB_VIDEO_MODE_TYPE_RGB
84 | GRUB_VIDEO_MODE_TYPE_ALPHA);
86 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
88 info_width = 500;
89 info_height = 100;
91 color = grub_video_map_rgb (0, 0, 0);
92 bg = color;
93 grub_video_fill_rect (color, 0, 0, width, height);
95 color = grub_video_map_rgb (255, 0, 0);
96 grub_video_fill_rect (color, 0, 0, 100, 100);
98 color = grub_video_map_rgb (0, 255, 255);
99 grub_video_fill_rect (color, 100, 100, 100, 100);
101 glyph = grub_font_get_glyph (fixed, '*');
102 grub_font_draw_glyph (glyph, color, 200 ,0);
104 grub_video_set_viewport (x + 150, y + 150,
105 width - 150 * 2, height - 150 * 2);
106 color = grub_video_map_rgb (77, 33, 77);
107 grub_video_fill_rect (color, 0, 0, width, height);
109 grub_video_set_active_render_target (text_layer);
111 color = grub_video_map_rgb (255, 255, 0);
112 grub_font_draw_string ("ABCDEFG", fixed, color, 16, 100);
113 color = grub_video_map_rgb (128, 128, 255);
114 grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
115 fixed, color, 16, 150);
117 color = grub_video_map_rgb (255, 255, 255);
118 glyph = grub_font_get_glyph (fixed, '*');
120 for (i = 0; i < 16; i++)
122 color = grub_video_map_color (i);
123 palette[i] = color;
124 grub_font_draw_glyph (glyph, color, 16 + i * 16, 220);
127 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
129 for (i = 0; i < 255; i++)
131 color = grub_video_map_rgb (i, 33, 77);
132 grub_video_fill_rect (color, 0, 0, width, height);
133 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, 0, 0,
134 0, 0, width, height);
137 color = grub_video_map_rgb (255, 255, 0);
138 grub_font_draw_string ("Press a key to continue.", fixed, color, 10, 60);
139 grub_video_swap_buffers ();
140 grub_getkey ();
141 grub_video_fill_rect (bg, 0, 0, info_width, info_height); /* Clear info. */
143 grub_errno = GRUB_ERR_NONE;
148 /* Simple opaque image blit test.
149 Returns the error status in grub_errno. */
150 static void
151 bitmap_demo (struct videotest_options *vt_opts)
153 if (grub_video_set_mode (preferred_mode_list, 0) != GRUB_ERR_NONE)
154 return;
155 grub_video_enable_double_buffering (vt_opts->double_buffering);
157 grub_video_rect_t view;
158 grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
159 (unsigned *) &view.width,
160 (unsigned *) &view.height);
162 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
163 const int bm1width = 500, bm1height = 400;
164 struct grub_video_bitmap *bitmap1;
166 if (grub_video_bitmap_create (&bitmap1, bm1width, bm1height,
167 GRUB_VIDEO_BLIT_FORMAT_RGB_888)
168 != GRUB_ERR_NONE)
169 return;
171 int offset = 0;
172 int x;
173 int y;
174 grub_uint8_t *data = grub_video_bitmap_get_data (bitmap1);
175 for (y = 0; y < bm1height; y++)
177 for (x = 0; x < bm1width; x++)
179 data[offset++] = x ^ y; /* red */
180 data[offset++] = (x * 3) ^ (y * 3); /* green */
181 data[offset++] = (x * 2) ^ (y * 2); /* blue */
185 /* Blit the entire bitmap in the center of the screen. */
186 grub_video_blit_bitmap (bitmap1,
187 GRUB_VIDEO_BLIT_REPLACE,
188 view.x + (view.width - bm1width) / 2,
189 view.y + (view.height - bm1height) / 2,
190 0, 0, bm1width, bm1height);
191 grub_video_swap_buffers ();
192 grub_getkey ();
194 /* Blit more copies of the bitmap. */
195 /* Upper left. */
196 grub_video_blit_bitmap (bitmap1, GRUB_VIDEO_BLIT_REPLACE,
197 view.x, view.y, 0, 0, bm1width, bm1height);
198 /* Upper right. */
199 grub_video_blit_bitmap (bitmap1,
200 GRUB_VIDEO_BLIT_REPLACE,
201 view.x + view.width - bm1width,
202 view.y, 0, 0, bm1width, bm1height);
203 /* Lower left. */
204 grub_video_blit_bitmap (bitmap1,
205 GRUB_VIDEO_BLIT_REPLACE,
206 view.x,
207 view.y + view.height - bm1height,
208 0, 0, bm1width, bm1height);
209 /* Lower right. */
210 grub_video_blit_bitmap (bitmap1,
211 GRUB_VIDEO_BLIT_REPLACE,
212 view.x + view.width - bm1width,
213 view.y + view.height - bm1height,
214 0, 0, bm1width, bm1height);
215 grub_video_swap_buffers ();
216 grub_getkey ();
218 int clearbg = 0; /* Boolean flag: whether to fill background. */
219 grub_video_color_t bgcolor = grub_video_map_rgb (16, 16, 96);
221 /* Animate the image sliding in. End when a key is pressed. */
222 int vscale = 1000;
223 int velocityx = -5000;
224 int velocityy = -8000;
225 int positionx = 100;
226 int positiony = 300;
228 grub_uint32_t frame_count = 0;
229 grub_uint32_t start_time = grub_get_time_ms ();
231 while (grub_checkkey () == -1)
233 /* If the time limit option is set, then check if it's exceeded. */
234 if (vt_opts->test_time != 0
235 && grub_get_time_ms () >= start_time + vt_opts->test_time * 1000)
236 break;
238 int newx = positionx + velocityx / vscale;
239 int newy = positiony + velocityy / vscale;
241 /* Check collision w/ left */
242 if (newx < view.x && velocityx < 0)
244 velocityx = -velocityx;
245 newx = positionx + velocityx / vscale;
247 /* Check collision w/ right */
248 if (newx + bm1width > view.x + view.width && velocityx > 0)
250 velocityx = -velocityx;
251 newx = positionx + velocityx / vscale;
253 /* Check collision w/ top */
254 if (newy < 0 && velocityy < 0)
256 velocityy = -velocityy;
257 newy = positiony + velocityy / vscale;
259 /* Check collision w/ bottom */
260 if (newy + bm1height > view.y + view.height && velocityy > 0)
262 velocityy = -velocityy;
263 newy = positiony + velocityy / vscale;
266 positionx = newx;
267 positiony = newy;
269 if (clearbg)
270 grub_video_fill_rect (bgcolor, view.x, view.y, view.width,
271 view.height);
273 grub_video_blit_bitmap (bitmap1,
274 GRUB_VIDEO_BLIT_REPLACE,
275 view.x + positionx,
276 view.y + positiony, 0, 0, bm1width, bm1height);
277 grub_video_swap_buffers ();
278 frame_count++;
280 /* Acceleration due to gravity...
281 * note that the y coordinate is increasing downward. */
282 velocityy += vscale / 7;
285 /* Calculate average frame rate. */
286 grub_uint32_t duration = grub_get_time_ms () - start_time;
287 grub_uint32_t fps_x10 = 10 * 1000 * frame_count / duration;
289 /* Eat the keystroke. */
290 if (grub_checkkey () != -1)
291 grub_getkey ();
293 grub_video_bitmap_destroy (bitmap1);
294 grub_video_restore ();
296 grub_printf ("Average frame rate: %d.%d fps\n", fps_x10 / 10, fps_x10 % 10);
298 grub_errno = GRUB_ERR_NONE;
303 /* Configuration settings for a benchmark run. */
304 struct benchmark_config
306 const char *modespec;
307 int use_rgba_bitmaps;
310 /* The video configurations to use for the benchmark. */
311 static struct benchmark_config benchmark_configs[] = {
312 {"320x200", 0},
313 {"640x480", 0},
314 {"1024x768", 0},
315 {"1024x768", 1},
318 #define NUM_BENCHMARK_CONFIGS (sizeof(benchmark_configs) \
319 / sizeof(benchmark_configs[0]))
321 struct benchmark_result
323 /* If set to 1, the test was able to run successfully;
324 0 means there was an error. */
325 int test_passed;
327 /* Dimensions of the video mode used. */
328 int width;
329 int height;
331 /* Bits per pixel for the video mode used. */
332 int bpp;
334 /* All fps are in fps * 10 to achieve one decimal place. */
335 /* Set to 0 to indicate the test could not be run. */
336 grub_int32_t fill_fps;
337 grub_int32_t blit_fps;
338 grub_int32_t blend_fps;
339 grub_int32_t text_ascii_cps;
340 grub_int32_t text_unicode_cps;
343 #define BENCHMARK_RESULT_FPS_SCALE 10
344 #define BENCHMARK_RESULT_CPS_SCALE 1
346 static void
347 move_rectangle_one_step (int *x, int *y,
348 int width, int height,
349 int *vx, int *vy, const grub_video_rect_t * bounds)
351 int newx = *x + *vx;
352 int newy = *y + *vy;
354 /* Check collision w/ left */
355 if (newx < bounds->x && *vx < 0)
357 *vx = -*vx;
358 newx = *x + *vx;
360 /* Check collision w/ right */
361 if (newx + width > bounds->x + bounds->width && *vx > 0)
363 *vx = -*vx;
364 newx = *x + *vx;
366 /* Check collision w/ top */
367 if (newy < 0 && *vy < 0)
369 *vy = -*vy;
370 newy = *y + *vy;
372 /* Check collision w/ bottom */
373 if (newy + height > bounds->y + bounds->height && *vy > 0)
375 *vy = -*vy;
376 newy = *y + *vy;
379 *x = newx;
380 *y = newy;
383 /* Get the length of a UTF-8 encoded character string. */
384 static int
385 strlen_utf8 (const char *utf8str)
387 int len;
388 const grub_uint8_t *ptr;
389 grub_uint32_t code;
391 for (len = 0, ptr = (const grub_uint8_t *) utf8str;
392 grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0; )
393 len++;
395 return len;
398 /* Test text rendering performance. */
399 static void
400 benchmark_text (const char *test_str,
401 grub_int32_t *cps_result,
402 struct videotest_options *vt_opts,
403 grub_video_rect_t *view)
405 grub_uint32_t char_count;
406 grub_uint64_t start_time;
407 grub_uint64_t desired_stop_time;
408 grub_uint32_t duration;
409 grub_video_color_t black;
410 grub_video_color_t text_colors[4];
411 grub_font_t font;
412 int phase;
413 int test_str_len;
415 test_str_len = strlen_utf8 (test_str);
416 black = grub_video_map_rgb (0, 0, 0);
417 text_colors[0] = grub_video_map_rgb (44, 44, 54);
418 text_colors[1] = grub_video_map_rgb (64, 64, 96);
419 text_colors[2] = grub_video_map_rgb (80, 80, 140);
420 text_colors[3] = grub_video_map_rgb (255, 255, 255);
421 font = grub_font_get ("unifont Regular 10");
423 char_count = 0;
424 start_time = grub_get_time_ms ();
425 desired_stop_time = start_time + vt_opts->test_time * 1000;
427 phase = 0;
428 while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
430 int color_index;
432 grub_video_fill_rect (black, 0, 0, view->width, view->height);
434 /* Draw a series of lines in different colors. */
435 for (color_index = 0; color_index < 4; color_index++)
437 int line_number;
439 for (line_number = 0; line_number < 20; line_number++)
441 int x;
442 int y;
444 x = 10 - color_index;
445 y = (10 - color_index
446 + (line_number + 1) * phase
447 + grub_font_get_height (font) * line_number
448 + grub_font_get_ascent (font));
449 grub_font_draw_string (test_str, font,
450 text_colors[color_index], x, y);
451 /* Note: Using grub_strlen is not UTF-8-safe. */
452 char_count += test_str_len;
456 phase += 2;
457 if (phase > 15)
458 phase = 0;
460 grub_video_swap_buffers ();
462 if (grub_checkkey () != -1)
463 grub_getkey (); /* Eat the keypress, if there was one. */
465 /* Calculate average frame rate. */
466 duration = grub_get_time_ms () - start_time;
467 if (duration == 0)
469 *cps_result = 0;
471 else
473 *cps_result = (BENCHMARK_RESULT_CPS_SCALE * 1000
474 * char_count / duration);
478 /* Run the benchmark test for a particular video mode, which is specified
479 by `*config'. The results of the test are stored in `*result'. */
480 static void
481 do_benchmark (const struct benchmark_config *config,
482 struct benchmark_result *result,
483 struct videotest_options *vt_opts)
485 struct grub_video_mode_info modeinfo;
487 result->test_passed = 0;
488 result->width = 0;
489 result->height = 0;
490 result->bpp = 0;
491 result->fill_fps = 0;
492 result->blit_fps = 0;
493 result->blend_fps = 0;
495 if (grub_video_set_mode (config->modespec, 0) != GRUB_ERR_NONE)
496 return;
497 grub_video_enable_double_buffering (vt_opts->double_buffering);
499 if (grub_video_get_info (&modeinfo) == GRUB_ERR_NONE)
501 result->width = modeinfo.width;
502 result->height = modeinfo.height;
503 result->bpp = modeinfo.bpp;
506 /* Full screen bitmap blit test. */
508 grub_video_rect_t view;
509 grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
510 (unsigned *) &view.width,
511 (unsigned *) &view.height);
513 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
516 /* For measuring timing. */
517 grub_uint32_t frame_count;
518 grub_uint64_t start_time;
519 grub_uint64_t desired_stop_time;
520 grub_uint32_t duration;
523 /*** FILL TEST ***/
525 /* Alternates between 0 and 1 to change the color. */
526 int color_flag = 0;
527 grub_video_color_t fillcolors[2];
528 fillcolors[0] = grub_video_map_rgb (0, 0, 255);
529 fillcolors[1] = grub_video_map_rgb (255, 255, 0);
531 frame_count = 0;
532 start_time = grub_get_time_ms ();
533 desired_stop_time = start_time + vt_opts->test_time * 1000;
535 while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
537 grub_video_fill_rect (fillcolors[color_flag],
538 view.x, view.y, view.width, view.height);
539 grub_video_swap_buffers ();
540 color_flag ^= 1;
541 frame_count++;
543 if (grub_checkkey () != -1)
544 grub_getkey (); /* Eat the keypress, if there was one. */
546 /* Calculate average frame rate. */
547 duration = grub_get_time_ms () - start_time;
548 if (duration == 0)
550 result->fill_fps = 0;
552 else
554 result->fill_fps =
555 (BENCHMARK_RESULT_FPS_SCALE * 1000
556 * frame_count / duration);
560 /*** BLIT TEST ***/
562 /* Generate two bitmaps, the same size as the screen. */
563 const int bitmapwidth = view.width, bitmapheight = view.height;
564 struct grub_video_bitmap *bitmap1;
565 struct grub_video_bitmap *bitmap2;
566 enum grub_video_blit_format bitmap_format = config->use_rgba_bitmaps
567 ? GRUB_VIDEO_BLIT_FORMAT_RGBA_8888 : GRUB_VIDEO_BLIT_FORMAT_RGB_888;
569 if (grub_video_bitmap_create (&bitmap1, bitmapwidth, bitmapheight,
570 bitmap_format) != GRUB_ERR_NONE)
571 return;
573 if (grub_video_bitmap_create (&bitmap2, bitmapwidth, bitmapheight,
574 bitmap_format) != GRUB_ERR_NONE)
576 grub_video_bitmap_destroy (bitmap1);
577 return;
580 int offset;
581 int x;
582 int y;
583 grub_uint8_t *data;
585 offset = 0;
586 data = grub_video_bitmap_get_data (bitmap1);
587 for (y = 0; y < bitmapheight; y++)
589 for (x = 0; x < bitmapwidth; x++)
591 data[offset++] = x ^ y; /* red */
592 data[offset++] = (x * 3) ^ (y * 3); /* green */
593 data[offset++] = (x * 2) ^ (y * 2); /* blue */
594 if (config->use_rgba_bitmaps)
595 data[offset++] = 255;
599 offset = 0;
600 data = grub_video_bitmap_get_data (bitmap2);
601 for (y = 0; y < bitmapheight; y++)
603 for (x = 0; x < bitmapwidth; x++)
605 data[offset++] = x + y; /* red */
606 data[offset++] = x * x + y * y; /* green */
607 data[offset++] = x * x / 4 + y * y / 4; /* blue */
608 if (config->use_rgba_bitmaps)
609 data[offset++] = 255;
614 /* Now do the blit test, alternating between the two bitmaps. */
615 frame_count = 0;
616 start_time = grub_get_time_ms ();
617 desired_stop_time = start_time + vt_opts->test_time * 1000;
619 int cur = 0; /* Which bitmap to draw this frame. */
620 while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
622 struct grub_video_bitmap *current_bitmap = cur == 0 ? bitmap1 : bitmap2;
623 grub_video_blit_bitmap (current_bitmap,
624 GRUB_VIDEO_BLIT_REPLACE,
625 view.x, view.y, 0, 0, bitmapwidth,
626 bitmapheight);
627 grub_video_swap_buffers ();
628 frame_count++;
629 cur ^= 1;
631 if (grub_checkkey () != -1)
632 grub_getkey (); /* Eat the keypress, if there was once. */
634 /* Calculate average frame rate. */
635 duration = grub_get_time_ms () - start_time;
636 if (duration == 0)
638 result->blit_fps = 0;
640 else
642 result->blit_fps =
643 (BENCHMARK_RESULT_FPS_SCALE * 1000
644 * frame_count / duration);
647 grub_video_bitmap_destroy (bitmap2);
648 grub_video_bitmap_destroy (bitmap1);
652 /*** BLEND TEST ***/
654 /* Generate two bitmaps, with alpha translucency. */
655 const int bbw = view.width * 2 / 3;
656 const int bbh = view.height * 2 / 3;
658 if (grub_video_bitmap_create (&bitmap1, bbw, bbh,
659 GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) !=
660 GRUB_ERR_NONE)
661 return;
663 if (grub_video_bitmap_create (&bitmap2, bbw, bbh,
664 GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) !=
665 GRUB_ERR_NONE)
667 grub_video_bitmap_destroy (bitmap1);
668 return;
671 offset = 0;
672 data = grub_video_bitmap_get_data (bitmap1);
673 for (y = 0; y < bbh; y++)
675 for (x = 0; x < bbw; x++)
677 /* Calculate a to be increasing away from the center. */
678 int dx = 256 * (x - bbw / 2) / (bbw / 2);
679 int dy = 256 * (y - bbh / 2) / (bbh / 2);
680 int a = dx * dx + dy * dy;
681 /* range for a = 0 .. 2*(256^2) = 2*2^16 = 2^17 */
682 a >>= 17 - 8; /* Make range 0..256. */
683 if (a > 255)
684 a = 255;
686 data[offset++] = x ^ y; /* red */
687 data[offset++] = (x * 3) ^ (y * 3); /* green */
688 data[offset++] = (x * 2) ^ (y * 2); /* blue */
689 data[offset++] = 255 - a;
693 offset = 0;
694 data = grub_video_bitmap_get_data (bitmap2);
695 for (y = 0; y < bbh; y++)
697 for (x = 0; x < bbw; x++)
699 data[offset++] = x + y; /* red */
700 data[offset++] = x * x + y * y; /* green */
701 data[offset++] = x * x / 4 + y * y / 4; /* blue */
702 data[offset++] = 255;
706 frame_count = 0;
707 start_time = grub_get_time_ms ();
708 desired_stop_time = start_time + vt_opts->test_time * 1000;
711 grub_video_color_t bgcolor = grub_video_map_rgb (80, 80, 80);
713 /* Bitmap locations. */
714 int b1x = 0;
715 int b1y = 0;
716 int b2x = view.width - bbw;
717 int b2y = 0;
718 /* Bitmap velocities. */
719 int b1vx = 8;
720 int b1vy = 12;
721 int b2vx = -10;
722 int b2vy = 9;
724 while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
726 move_rectangle_one_step (&b1x, &b1y, bbw, bbh, &b1vx, &b1vy, &view);
727 move_rectangle_one_step (&b2x, &b2y, bbw, bbh, &b2vx, &b2vy, &view);
728 grub_video_fill_rect (bgcolor, view.x, view.y, view.width, view.height);
729 grub_video_blit_bitmap (bitmap2,
730 GRUB_VIDEO_BLIT_BLEND,
731 b2x, b2y, 0, 0, bbw, bbh);
732 grub_video_blit_bitmap (bitmap1,
733 GRUB_VIDEO_BLIT_BLEND,
734 b1x, b1y, 0, 0, bbw, bbh);
735 grub_video_swap_buffers ();
736 frame_count++;
737 cur ^= 1;
739 if (grub_checkkey () != -1)
740 grub_getkey (); /* Eat the keypress, if there was once. */
742 /* Calculate average frame rate. */
743 duration = grub_get_time_ms () - start_time;
744 if (duration == 0)
746 result->blend_fps = 0;
748 else
750 result->blend_fps =
751 (BENCHMARK_RESULT_FPS_SCALE * 1000
752 * frame_count / duration);
755 grub_video_bitmap_destroy (bitmap2);
756 grub_video_bitmap_destroy (bitmap1);
758 /* Text benchmark with 104 characters of English ASCII text. */
759 benchmark_text ("The quick brown fox jumped over the lazy dog. "
760 "(1234567890). "
761 "THE RAIN IN SPAIN FALLS MAINLY ON THE PLAIN.",
762 &result->text_ascii_cps, vt_opts, &view);
763 /* Text benchmark with 104 Unicode characters pseudorandomly uniformly
764 distributed over the characters provided by GNU unifont. The string is
765 UTF-8 encoded. */
766 benchmark_text ("\xE4\x94\x93\xEB\x83\xA6\xE2\x94\x85\xEB\xA8\xB1\xEE\x81"
767 "\xA3\xDD\x9D\xEA\xBC\xA4\xE1\xA3\x86\xEE\x8C\xA5\xE5\x8A"
768 "\x81\xEC\x99\x8A\xE0\xAE\xA1\xE8\xB4\xAC\xE4\x9A\xBD\xE6"
769 "\xB5\xAD\xED\xA4\x98\xEA\x88\x92\xE7\xA2\x9C\xEE\xAC\x8C"
770 "\xE9\x95\x9C\xE5\xB0\x89\xEB\x82\xA2\xE3\x9E\x89\xE8\xA4"
771 "\x87\xE4\xAC\xA0\xE8\x89\xA4\xE7\x8E\xAC\xE6\xA2\x95\xEE"
772 "\xAC\xB9\xE5\x9C\x8D\xEC\x8A\xA5\xE6\xB5\xA2\xE1\xA5\xBA"
773 "\xE2\x93\x80\xE6\x92\xA9\xE3\x9B\xB3\xE2\xB0\x9D\xE2\x95"
774 "\x94\xE7\xAD\x89\xE2\x83\x88\xEA\x8D\xA5\xE5\x8C\x99\xE5"
775 "\x9F\xB9\xE4\x88\x97\xEC\x95\xA6\xC9\xBD\xE5\xA1\x86\xE7"
776 "\xA3\xBE\xEA\x9A\xA9\xE5\x93\x98\xE4\xAD\xB1\xE1\x90\xB8"
777 "\xE4\x8A\x91\xE8\x8B\xBA\xE9\xB5\x80\xE8\xB6\xB1\xE4\x89"
778 "\xB4\xE4\xB8\x82\xDF\x8C\xE6\xAB\x83\xEA\x94\x8F\xEC\xA9"
779 "\xB1\xED\xA0\xA6\xEB\xBA\x89\xE2\xB1\x88\xE7\xA7\xA5\xE3"
780 "\x8A\x92\xE5\xA1\xA5\xEC\xAB\x89\xEA\xB7\x9B\xEA\x92\xBE"
781 "\xEA\xAD\x85\xE3\xB8\x8A\xE0\xB8\xBD\xEE\xB5\x9C\xE1\x93"
782 "\xB7\xE3\xB1\x8A\xE8\x8A\xB8\xEB\xA6\x85\xEE\x8B\xB4\xE1"
783 "\x92\xA7\xE4\x88\x8C\xE0\xA2\xB2\xE5\x9C\xB8\xEC\x94\x86"
784 "\xED\x86\x82\xE2\x87\xBF\xE1\xA4\x81\xE3\x84\x8A\xE2\xA7"
785 "\x8B\xE8\x8F\x84\xED\x98\x9A\xE3\x85\x92\xE9\xA4\x80\xED"
786 "\x86\xB9\xE5\xB6\x9A\xE4\xBF\xBC\xE1\x97\x92\xEE\x86\x90"
787 "\xE2\xB1\x8B\xC3\x83\xEC\x8D\xA4\xED\x9E\x90\xE3\xBB\x8E",
788 &result->text_unicode_cps, vt_opts, &view);
790 grub_video_restore ();
791 result->test_passed = 1;
794 /* Run a benchmark test in a series of video modes.
795 The results are reported in tabular form. This will be helpful to
796 determine how effective various optimizations are. */
797 static void
798 benchmark_test (struct videotest_options *vt_opts)
800 unsigned int i;
801 struct benchmark_result results[NUM_BENCHMARK_CONFIGS];
803 /* Set option default values. */
804 if (vt_opts->test_time == 0)
805 vt_opts->test_time = DEFAULT_TEST_TIME;
807 /* Run benchmarks. */
808 for (i = 0; i < NUM_BENCHMARK_CONFIGS; i++)
810 grub_error_push ();
811 do_benchmark (&benchmark_configs[i], &results[i], vt_opts);
814 grub_print_error ();
816 /* Display results. */
817 grub_printf ("Benchmark results (in frames/s):\n");
818 grub_printf ("(W=Width, H=Height, B=Bits per pixel, A=Bitmap Alpha)\n");
819 grub_printf (" TEXT chars/s\n");
820 grub_printf (" W H B A FILL BLIT BLEND ASCII UNICODE\n");
821 for (i = 0; i < NUM_BENCHMARK_CONFIGS; i++)
823 struct benchmark_config *c = &benchmark_configs[i];
824 struct benchmark_result *r = &results[i];
826 if (r->test_passed)
828 grub_printf ("%4dx%4d %2d %d: %4d.%d %4d.%d %4d.%d %5d %5d\n",
829 r->width, r->height, r->bpp,
830 c->use_rgba_bitmaps,
831 r->fill_fps / BENCHMARK_RESULT_FPS_SCALE,
832 r->fill_fps % BENCHMARK_RESULT_FPS_SCALE,
833 r->blit_fps / BENCHMARK_RESULT_FPS_SCALE,
834 r->blit_fps % BENCHMARK_RESULT_FPS_SCALE,
835 r->blend_fps / BENCHMARK_RESULT_FPS_SCALE,
836 r->blend_fps % BENCHMARK_RESULT_FPS_SCALE,
837 r->text_ascii_cps / BENCHMARK_RESULT_CPS_SCALE,
838 r->text_unicode_cps / BENCHMARK_RESULT_CPS_SCALE);
840 else
842 grub_printf ("%s Not supported.\n", c->modespec);
846 grub_errno = GRUB_ERR_NONE;
850 /* Test time functions. */
851 static void
852 clock_test (struct videotest_options *vt_opts)
854 if (grub_video_set_mode ("640x480", 0) != GRUB_ERR_NONE)
855 return;
856 grub_video_enable_double_buffering (vt_opts->double_buffering);
858 grub_video_rect_t view;
859 grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
860 (unsigned *) &view.width,
861 (unsigned *) &view.height);
863 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
865 /* Draw a progress bar that animates in sync with time. */
867 grub_video_rect_t bar_frame;
868 bar_frame.width = view.width - 2 * view.width / 10;
869 bar_frame.height = view.height / 20;
870 bar_frame.x = view.x + view.width / 10;
871 bar_frame.y = view.y + view.height - bar_frame.height - view.height / 10;
873 grub_video_color_t bgcolor = grub_video_map_rgb (50, 50, 50);
874 grub_video_color_t framecolor = grub_video_map_rgb (255, 255, 255);
875 grub_video_color_t barbgcolor = grub_video_map_rgb (0, 0, 128);
876 grub_video_color_t barcolor = grub_video_map_rgb (100, 100, 255);
878 grub_uint32_t frame_count;
879 grub_uint64_t start_time;
880 grub_uint64_t barstart;
881 grub_uint32_t barlength = 1000;
883 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
885 frame_count = 0;
886 start_time = grub_get_time_ms ();
887 barstart = grub_get_time_ms ();
889 while (grub_checkkey () == -1)
891 grub_uint64_t now;
892 grub_uint32_t bartime;
893 now = grub_get_time_ms ();
894 /* If the time limit option is set, then check if it's exceeded. */
895 if (vt_opts->test_time != 0
896 && now >= start_time + vt_opts->test_time * 1000)
897 break;
898 bartime = now - barstart;
899 if (bartime > barlength)
901 barstart = grub_get_time_ms (); /* Start over. */
902 bartime = barlength;
905 /* Clear screen. */
906 grub_video_fill_rect (bgcolor, view.x, view.y, view.width, view.height);
908 /* Border. */
909 grub_video_fill_rect (framecolor,
910 bar_frame.x - 1, bar_frame.y - 1,
911 bar_frame.width + 2, bar_frame.height + 2);
913 /* Bar background. */
914 int barwidth = bar_frame.width * bartime / barlength;
915 grub_video_fill_rect (barbgcolor, bar_frame.x + barwidth,
916 bar_frame.y, bar_frame.width - barwidth,
917 bar_frame.height);
918 /* Bar foreground. */
919 grub_video_fill_rect (barcolor, bar_frame.x, bar_frame.y,
920 barwidth, bar_frame.height);
921 grub_video_swap_buffers ();
922 frame_count++;
925 grub_uint32_t duration = grub_get_time_ms () - start_time;
926 grub_uint32_t fps_x10 = 10 * 1000 * frame_count / duration;
928 if (grub_checkkey () != -1)
929 grub_getkey (); /* Eat the keypress, if there was one. */
930 grub_video_restore ();
931 grub_printf ("Average frame rate: %d.%d fps\n", fps_x10 / 10, fps_x10 % 10);
935 /* Test double buffering. */
936 static void
937 doublebuf_test (struct videotest_options *vt_opts)
939 if (grub_video_set_mode ("640x480", 0) != GRUB_ERR_NONE)
940 return;
941 grub_video_enable_double_buffering (vt_opts->double_buffering);
943 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
945 grub_video_color_t red = grub_video_map_rgb (255, 50, 50);
946 grub_video_color_t yellow = grub_video_map_rgb (255, 255, 0);
947 grub_video_color_t green = grub_video_map_rgb (20, 255, 20);
948 grub_video_color_t blue = grub_video_map_rgb (50, 50, 255);
949 grub_video_color_t black = grub_video_map_rgb (0, 0, 0);
950 grub_video_color_t bgcolor = grub_video_map_rgb (255, 255, 255);
952 grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
953 grub_video_fill_rect (red, 100, 100, 200, 200);
954 grub_video_swap_buffers ();
955 grub_getkey ();
957 grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
958 grub_video_fill_rect (yellow, 120, 120, 200, 200);
959 grub_video_swap_buffers ();
960 grub_getkey ();
962 grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
963 grub_video_fill_rect (green, 140, 140, 200, 200);
964 grub_video_swap_buffers ();
965 grub_getkey ();
967 grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
968 grub_video_fill_rect (blue, 160, 160, 200, 200);
969 grub_video_swap_buffers ();
970 grub_getkey ();
972 grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
973 grub_video_fill_rect (black, 180, 180, 200, 200);
974 grub_video_swap_buffers ();
975 grub_getkey ();
977 grub_video_restore ();
981 /* Test text rendering. */
982 static void
983 text_test (struct videotest_options *vt_opts)
985 grub_video_color_t color;
986 const char *s;
987 int view_x;
988 int view_y;
989 int view_width;
990 int view_height;
991 int xpos;
992 int ypos;
993 int i;
994 grub_font_t font1;
995 grub_font_t font2;
996 grub_font_t font3;
997 grub_font_t sansbig;
998 grub_font_t sans;
999 grub_font_t sanssmall;
1000 grub_font_t fixed;
1002 if (grub_video_set_mode (preferred_mode_list, 0) != GRUB_ERR_NONE)
1003 return;
1004 grub_video_enable_double_buffering (vt_opts->double_buffering);
1006 grub_video_get_viewport ((unsigned int *) &view_x,
1007 (unsigned int *) &view_y,
1008 (unsigned int *) &view_width,
1009 (unsigned int *) &view_height);
1010 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
1012 if (!(font1 = grub_font_get ("New Century Schoolbook Regular 24"))
1013 || !(font2 = grub_font_get ("Helvetica Bold 14"))
1014 || !(font3 = grub_font_get ("Helvetica Regular 10"))
1015 || !(sansbig = grub_font_get ("Helvetica Bold 24"))
1016 || !(sans = grub_font_get ("Helvetica Bold 14"))
1017 || !(sanssmall = grub_font_get ("Helvetica Regular 8"))
1018 || !(fixed = grub_font_get ("Fixed Regular 20")))
1020 grub_video_restore ();
1021 grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
1022 return;
1025 color = grub_video_map_rgb (0, 0, 0);
1026 grub_video_fill_rect (color, 0, 0, view_width, view_height);
1028 color = grub_video_map_rgb (255, 0, 0);
1029 grub_video_fill_rect (color, 0, 0, 100, 100);
1031 color = grub_video_map_rgb (0, 255, 255);
1032 grub_video_fill_rect (color, 100, 100, 100, 100);
1034 color = grub_video_map_rgb (255, 255, 255);
1036 xpos = 10;
1037 ypos = 30;
1038 s = "Hello, World!";
1039 for (i = 0; i < 24; i++)
1041 if (xpos + grub_font_get_string_width (font1, s) >= view_width)
1043 /* The string will wrap; go to the beginning of the next line. */
1044 xpos = 10;
1045 ypos += (grub_font_get_descent (font1)
1046 + grub_font_get_ascent (font1));
1048 grub_font_draw_string ("Hello, World!",
1049 font1, grub_video_map_rgb (255, 255, 0),
1050 xpos, ypos);
1052 xpos += grub_font_get_string_width (font1, s);
1055 xpos = 240;
1056 ypos = 280;
1057 grub_font_draw_string (grub_font_get_name (font1),
1058 font1, grub_video_map_rgb (255, 255, 255),
1059 xpos, ypos);
1060 ypos += grub_font_get_descent (font1) + grub_font_get_ascent (font2) + 2;
1061 grub_font_draw_string (grub_font_get_name (font2),
1062 font2, grub_video_map_rgb (255, 255, 255),
1063 xpos, ypos);
1064 ypos += grub_font_get_descent (font2) + grub_font_get_ascent (font3) + 2;
1065 grub_font_draw_string (grub_font_get_name (font3),
1066 font3, grub_video_map_rgb (255, 255, 255),
1067 xpos, ypos);
1069 ypos += 40; /* Spacing. */
1071 grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
1072 sans, color, view_x + 16, ypos);
1073 ypos += grub_font_get_descent (sans) + grub_font_get_leading (sans);
1075 ypos += grub_font_get_ascent (fixed);
1076 grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
1077 fixed, color, 16, ypos);
1078 ypos += grub_font_get_descent (fixed) + grub_font_get_leading (fixed);
1080 ypos += 40; /* Spacing. */
1082 /* To convert Unicode characters into UTF-8 for this test, the following
1083 command is useful:
1084 echo -ne '\x00\x00\x26\x3A' | iconv -f UTF-32BE -t UTF-8 | od -t x1
1085 This converts the Unicode character U+263A to UTF-8. */
1087 /* Characters used:
1088 Code point Description UTF-8 encoding
1089 ----------- ------------------------------ --------------
1090 U+263A unfilled smiley face E2 98 BA
1091 U+00A1 inverted exclamation point C2 A1
1092 U+00A3 British pound currency symbol C2 A3
1093 U+03C4 Greek tau CF 84
1094 U+00E4 lowercase letter a with umlaut C3 A4
1095 U+2124 set 'Z' symbol (integers) E2 84 A4
1096 U+2287 subset symbol E2 8A 87
1097 U+211D set 'R' symbol (real numbers) E2 84 9D */
1100 "Unicode test: happy\xE2\x98\xBA \xC2\xA3 5.00"
1101 " \xC2\xA1\xCF\x84\xC3\xA4u! "
1102 " \xE2\x84\xA4\xE2\x8A\x87\xE2\x84\x9D";
1103 color = grub_video_map_rgb (128, 128, 255);
1105 /* All characters in the string exist in the 'Fixed 20' (10x20) font. */
1106 ypos += grub_font_get_ascent (fixed);
1107 grub_font_draw_string (s, fixed, color, 16, ypos);
1108 ypos += grub_font_get_descent (fixed) + grub_font_get_leading (fixed);
1110 /* Some characters don't exist in the Helvetica font, so the font engine
1111 may fall back to using glyphs from another font that has them. */
1113 ypos += grub_font_get_ascent (sansbig);
1114 grub_font_draw_string (s, sansbig, color, 16, ypos);
1115 ypos += grub_font_get_descent (sansbig) + grub_font_get_leading (sansbig);
1117 ypos += grub_font_get_ascent (sans);
1118 grub_font_draw_string (s, sans, color, 16, ypos);
1119 ypos += grub_font_get_descent (sans) + grub_font_get_leading (sans);
1121 ypos += grub_font_get_ascent (sanssmall);
1122 grub_font_draw_string (s, sanssmall, color, 16, ypos);
1123 ypos += (grub_font_get_descent (sanssmall)
1124 + grub_font_get_leading (sanssmall));
1127 grub_video_swap_buffers ();
1128 grub_getkey ();
1129 grub_video_restore ();
1130 grub_errno = GRUB_ERR_NONE;
1134 /* Test bitmap scaling. */
1135 static void
1136 scale_test (struct videotest_options *vt_opts)
1138 if (grub_video_set_mode (preferred_mode_list, 0) != GRUB_ERR_NONE)
1139 return;
1140 grub_video_enable_double_buffering (vt_opts->double_buffering);
1142 grub_errno = GRUB_ERR_NONE;
1143 grub_video_rect_t view;
1144 grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
1145 (unsigned *) &view.width,
1146 (unsigned *) &view.height);
1148 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
1150 grub_font_t font;
1151 if (!(font = grub_font_get ("Helvetica Regular 10")))
1153 grub_video_restore ();
1154 grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
1155 return;
1158 grub_video_color_t color;
1160 int text_y = 0;
1161 int text_height = 25;
1163 color = grub_video_map_rgb (44, 44, 200);
1164 grub_video_fill_rect (color, view.x, view.y, view.width, view.height);
1165 color = grub_video_map_rgb (255, 255, 255);
1167 grub_font_draw_string ("Loading image",
1168 font, color, 10, text_y += text_height);
1170 enum grub_video_bitmap_scale_method scale_method =
1171 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST;
1172 const char *bitmap_name = "/boot/grub/themes/winter/without-leaves.png";
1173 struct grub_video_bitmap *bitmap;
1174 grub_video_bitmap_load (&bitmap, bitmap_name);
1175 if (grub_errno != GRUB_ERR_NONE)
1177 grub_font_draw_string ("Error loading bitmap",
1178 font, color, 10, text_y += text_height);
1180 else
1182 grub_font_draw_string ("Original image",
1183 font, color, 10, text_y += text_height);
1184 grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_BLEND,
1185 400, text_y - 10,
1186 0, 0, grub_video_bitmap_get_width (bitmap),
1187 grub_video_bitmap_get_height (bitmap));
1189 struct grub_video_bitmap *bitmap2;
1190 if (grub_video_bitmap_create_scaled (&bitmap2, 40, 40,
1191 bitmap,
1192 scale_method)
1193 != GRUB_ERR_NONE)
1195 grub_font_draw_string ("Error scaling down bitmap",
1196 font, color, 10, text_y += text_height);
1198 else
1200 grub_font_draw_string ("Scaled down version",
1201 font, color, 10, text_y += text_height);
1202 grub_video_blit_bitmap (bitmap2, GRUB_VIDEO_BLIT_BLEND,
1203 400, text_y + 100,
1204 0, 0, grub_video_bitmap_get_width (bitmap2),
1205 grub_video_bitmap_get_height (bitmap2));
1206 grub_video_bitmap_destroy (bitmap2);
1209 struct grub_video_bitmap *bitmap3;
1210 if (grub_video_bitmap_create_scaled (&bitmap3, 500, 300, bitmap,
1211 scale_method)
1212 != GRUB_ERR_NONE)
1214 grub_font_draw_string ("Error scaling up bitmap",
1215 font, color, 10, text_y += text_height);
1217 else
1219 grub_font_draw_string ("Scaled up version",
1220 font, color, 10, text_y += text_height);
1221 grub_video_blit_bitmap (bitmap3, GRUB_VIDEO_BLIT_BLEND,
1222 400, text_y + 50,
1223 0, 0, grub_video_bitmap_get_width (bitmap3),
1224 grub_video_bitmap_get_height (bitmap3));
1225 grub_video_bitmap_destroy (bitmap3);
1229 grub_video_swap_buffers ();
1230 grub_getkey ();
1231 grub_video_bitmap_destroy (bitmap);
1232 grub_video_restore ();
1236 /* Print a list of the available tests. */
1237 static void list_tests (void);
1240 Video test command. Takes an argument specifying the test to run.
1242 static grub_err_t
1243 grub_cmd_videotest (grub_extcmd_t cmd, int argc, char **args)
1245 struct grub_arg_list *state = cmd->state;
1246 int i;
1247 struct videotest_options vt_opts;
1248 /* Pointer to the test function. */
1249 void (*test_func) (struct videotest_options *) = NULL;
1251 vt_opts.test_time =
1252 state[ARGINDEX_TEST_TIME].set
1253 ? grub_strtoul (state[ARGINDEX_TEST_TIME].arg, 0, 0) : 0;
1254 vt_opts.double_buffering = state[ARGINDEX_DOUBLE_BUF].set;
1256 /* Parse command line arguments to determine the test to run. */
1257 for (i = 0; i < argc; i++)
1259 char *arg = args[i];
1260 if (grub_strcmp (arg, "list") == 0)
1262 list_tests ();
1263 return GRUB_ERR_NONE;
1265 else if (grub_strcmp (arg, "basic") == 0)
1267 test_func = basic_video_test;
1269 else if (grub_strcmp (arg, "bench") == 0)
1271 test_func = benchmark_test;
1273 else if (grub_strcmp (arg, "bitmaps") == 0)
1275 test_func = bitmap_demo;
1277 else if (grub_strcmp (arg, "clock") == 0)
1279 test_func = clock_test;
1281 else if (grub_strcmp (arg, "doublebuf") == 0)
1283 test_func = doublebuf_test;
1285 else if (grub_strcmp (arg, "text") == 0)
1287 test_func = text_test;
1289 else if (grub_strcmp (arg, "scale") == 0)
1291 test_func = scale_test;
1293 else
1295 grub_printf ("Error: Unknown test `%s'\n", arg);
1296 grub_errno = GRUB_ERR_BAD_ARGUMENT;
1297 return grub_errno;
1301 if (test_func == NULL)
1303 grub_printf ("Usage: videotest TESTNAME Run a test.\n");
1304 grub_printf (" videotest list List available tests.\n");
1305 grub_printf ("\n");
1306 list_tests ();
1308 else
1310 test_func (&vt_opts);
1313 return grub_errno;
1316 static void
1317 list_tests (void)
1319 grub_printf ("Available tests\n");
1320 grub_printf ("===============\n");
1321 grub_printf ("basic Basic video test with filled rectangles,\n");
1322 grub_printf (" offscreen rendering targets, some text.\n");
1323 grub_printf ("bench Run a performance benchmark.\n");
1324 grub_printf ("bitmaps Test generating and blitting bitmaps.\n");
1325 grub_printf ("clock Test time functions w/ animated progress bar.\n");
1326 grub_printf ("doublebuf Test double buffering.\n");
1327 grub_printf ("text Test text rendering.\n");
1328 grub_printf ("scale Test image scaling.\n");
1329 grub_printf ("\n");
1332 static grub_extcmd_t cmd;
1334 GRUB_MOD_INIT (videotest)
1336 cmd = grub_register_extcmd ("videotest",
1337 grub_cmd_videotest,
1338 GRUB_COMMAND_FLAG_BOTH,
1339 "videotest TEST",
1340 "Run the specified video subsystem test.",
1341 arg_options);
1344 GRUB_MOD_FINI (videotest)
1346 grub_unregister_extcmd (cmd);