2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2013 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 /* All tests need to include test.h for GRUB testing framework. */
23 #include <grub/test.h>
25 #include <grub/video.h>
26 #include <grub/lib/crc.h>
28 #include <grub/term.h>
29 #ifdef GRUB_MACHINE_EMU
30 #include <grub/emu/hostdisk.h>
31 #include <grub/emu/misc.h>
34 GRUB_MOD_LICENSE ("GPLv3+");
38 static char *basename
;
39 static const grub_uint32_t
*checksums
;
40 static struct grub_video_mode_info capt_mode_info
;
42 struct grub_video_mode_info grub_test_video_modes
[GRUB_TEST_VIDEO_ALL_N_MODES
] = {
47 .mode_type
= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
,
50 .number_of_colors
= GRUB_VIDEO_FBSTD_NUMCOLORS
56 .mode_type
= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
,
59 .number_of_colors
= GRUB_VIDEO_FBSTD_NUMCOLORS
65 .mode_type
= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
,
68 .number_of_colors
= GRUB_VIDEO_FBSTD_NUMCOLORS
74 GRUB_VIDEO_MI_RGBA8888()
80 GRUB_VIDEO_MI_RGBA8888()
86 GRUB_VIDEO_MI_RGBA8888()
92 GRUB_VIDEO_MI_RGBA8888()
98 .mode_type
= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
,
100 .bytes_per_pixel
= 1,
101 .number_of_colors
= GRUB_VIDEO_FBSTD_EXT_NUMCOLORS
107 .mode_type
= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
,
109 .bytes_per_pixel
= 1,
110 .number_of_colors
= GRUB_VIDEO_FBSTD_EXT_NUMCOLORS
116 .mode_type
= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
,
118 .bytes_per_pixel
= 1,
119 .number_of_colors
= GRUB_VIDEO_FBSTD_EXT_NUMCOLORS
129 GRUB_VIDEO_MI_RGB555 ()
135 GRUB_VIDEO_MI_RGB555 ()
141 GRUB_VIDEO_MI_RGB555 ()
147 GRUB_VIDEO_MI_RGB565 ()
153 GRUB_VIDEO_MI_RGB565 ()
159 GRUB_VIDEO_MI_RGB565 ()
165 GRUB_VIDEO_MI_RGB888 ()
171 GRUB_VIDEO_MI_RGB888 ()
177 GRUB_VIDEO_MI_RGB888 ()
183 GRUB_VIDEO_MI_BGR555 ()
189 GRUB_VIDEO_MI_BGR555 ()
195 GRUB_VIDEO_MI_BGR555 ()
201 GRUB_VIDEO_MI_BGR565 ()
207 GRUB_VIDEO_MI_BGR565 ()
213 GRUB_VIDEO_MI_BGR565 ()
219 GRUB_VIDEO_MI_BGR888 ()
225 GRUB_VIDEO_MI_BGR888 ()
231 GRUB_VIDEO_MI_BGR888 ()
237 GRUB_VIDEO_MI_BGRA8888()
243 GRUB_VIDEO_MI_BGRA8888()
249 GRUB_VIDEO_MI_BGRA8888()
253 #ifdef GRUB_MACHINE_EMU
254 #include <grub/emu/hostfile.h>
258 grub_uint8_t magic
[2];
259 grub_uint32_t filesize
;
260 grub_uint32_t reserved
;
261 grub_uint32_t bmp_off
;
262 grub_uint32_t head_size
;
264 grub_uint16_t height
;
265 grub_uint16_t planes
;
270 grub_video_capture_write_bmp (const char *fname
,
272 const struct grub_video_mode_info
*mode_info
)
274 grub_util_fd_t fd
= grub_util_fd_open (fname
, GRUB_UTIL_FD_O_WRONLY
| GRUB_UTIL_FD_O_CREATTRUNC
);
275 struct bmp_header head
;
277 if (!GRUB_UTIL_FD_IS_VALID (fd
))
279 grub_printf (_("cannot open `%s': %s"),
280 fname
, grub_util_fd_strerror ());
283 grub_memset (&head
, 0, sizeof (head
));
288 if (mode_info
->mode_type
& GRUB_VIDEO_MODE_TYPE_RGB
)
290 head
.filesize
= grub_cpu_to_le32 (sizeof (head
) + mode_info
->width
* mode_info
->height
* 3);
291 head
.bmp_off
= grub_cpu_to_le32_compile_time (sizeof (head
));
292 head
.bpp
= grub_cpu_to_le16_compile_time (24);
296 head
.filesize
= grub_cpu_to_le32 (sizeof (head
) + 3 * 256 + mode_info
->width
* mode_info
->height
);
297 head
.bmp_off
= grub_cpu_to_le32_compile_time (sizeof (head
) + 3 * 256);
298 head
.bpp
= grub_cpu_to_le16_compile_time (8);
300 head
.head_size
= grub_cpu_to_le32_compile_time (sizeof (head
) - 14);
301 head
.width
= grub_cpu_to_le16 (mode_info
->width
);
302 head
.height
= grub_cpu_to_le16 (mode_info
->height
);
303 head
.planes
= grub_cpu_to_le16_compile_time (1);
305 head
.width
= grub_cpu_to_le16 (mode_info
->width
);
306 head
.height
= grub_cpu_to_le16 (mode_info
->height
);
308 grub_util_fd_write (fd
, (char *) &head
, sizeof (head
));
310 if (!(mode_info
->mode_type
& GRUB_VIDEO_MODE_TYPE_RGB
))
312 struct grub_video_palette_data palette_data
[256];
314 int palette_len
= mode_info
->number_of_colors
;
315 grub_memset (palette_data
, 0, sizeof (palette_data
));
316 if (palette_len
> 256)
318 grub_video_get_palette (0, palette_len
, palette_data
);
319 for (i
= 0; i
< 256; i
++)
321 grub_uint8_t r
, g
, b
;
322 r
= palette_data
[i
].r
;
323 g
= palette_data
[i
].g
;
324 b
= palette_data
[i
].b
;
326 grub_util_fd_write (fd
, (char *) &b
, 1);
327 grub_util_fd_write (fd
, (char *) &g
, 1);
328 grub_util_fd_write (fd
, (char *) &r
, 1);
332 /* This does essentialy the same as some fbblit functions yet using
333 them would mean testing them against themselves so keep this
334 implemetation separate. */
335 switch (mode_info
->bytes_per_pixel
)
339 grub_uint8_t
*buffer
= xmalloc (mode_info
->width
* 3);
340 grub_uint32_t rmask
= ((1 << mode_info
->red_mask_size
) - 1);
341 grub_uint32_t gmask
= ((1 << mode_info
->green_mask_size
) - 1);
342 grub_uint32_t bmask
= ((1 << mode_info
->blue_mask_size
) - 1);
343 int rshift
= mode_info
->red_field_pos
;
344 int gshift
= mode_info
->green_field_pos
;
345 int bshift
= mode_info
->blue_field_pos
;
346 int mulrshift
= (8 - mode_info
->red_mask_size
);
347 int mulgshift
= (8 - mode_info
->green_mask_size
);
348 int mulbshift
= (8 - mode_info
->blue_mask_size
);
351 for (y
= mode_info
->height
- 1; y
>= 0; y
--)
353 grub_uint32_t
*iptr
= (grub_uint32_t
*) ptr
+ (mode_info
->pitch
/ 4) * y
;
355 grub_uint8_t
*optr
= buffer
;
356 for (x
= 0; x
< (int) mode_info
->width
; x
++)
358 grub_uint32_t val
= *iptr
++;
359 *optr
++ = ((val
>> bshift
) & bmask
) << mulbshift
;
360 *optr
++ = ((val
>> gshift
) & gmask
) << mulgshift
;
361 *optr
++ = ((val
>> rshift
) & rmask
) << mulrshift
;
363 grub_util_fd_write (fd
, (char *) buffer
, mode_info
->width
* 3);
370 grub_uint8_t
*buffer
= xmalloc (mode_info
->width
* 3);
371 grub_uint32_t rmask
= ((1 << mode_info
->red_mask_size
) - 1);
372 grub_uint32_t gmask
= ((1 << mode_info
->green_mask_size
) - 1);
373 grub_uint32_t bmask
= ((1 << mode_info
->blue_mask_size
) - 1);
374 int rshift
= mode_info
->red_field_pos
;
375 int gshift
= mode_info
->green_field_pos
;
376 int bshift
= mode_info
->blue_field_pos
;
377 int mulrshift
= (8 - mode_info
->red_mask_size
);
378 int mulgshift
= (8 - mode_info
->green_mask_size
);
379 int mulbshift
= (8 - mode_info
->blue_mask_size
);
382 for (y
= mode_info
->height
- 1; y
>= 0; y
--)
384 grub_uint8_t
*iptr
= ((grub_uint8_t
*) ptr
+ mode_info
->pitch
* y
);
386 grub_uint8_t
*optr
= buffer
;
387 for (x
= 0; x
< (int) mode_info
->width
; x
++)
389 grub_uint32_t val
= 0;
390 #ifdef GRUB_CPU_WORDS_BIGENDIAN
391 val
|= *iptr
++ << 16;
397 val
|= *iptr
++ << 16;
399 *optr
++ = ((val
>> bshift
) & bmask
) << mulbshift
;
400 *optr
++ = ((val
>> gshift
) & gmask
) << mulgshift
;
401 *optr
++ = ((val
>> rshift
) & rmask
) << mulrshift
;
403 grub_util_fd_write (fd
, (char *) buffer
, mode_info
->width
* 3);
410 grub_uint8_t
*buffer
= xmalloc (mode_info
->width
* 3);
411 grub_uint16_t rmask
= ((1 << mode_info
->red_mask_size
) - 1);
412 grub_uint16_t gmask
= ((1 << mode_info
->green_mask_size
) - 1);
413 grub_uint16_t bmask
= ((1 << mode_info
->blue_mask_size
) - 1);
414 int rshift
= mode_info
->red_field_pos
;
415 int gshift
= mode_info
->green_field_pos
;
416 int bshift
= mode_info
->blue_field_pos
;
417 int mulrshift
= (8 - mode_info
->red_mask_size
);
418 int mulgshift
= (8 - mode_info
->green_mask_size
);
419 int mulbshift
= (8 - mode_info
->blue_mask_size
);
422 for (y
= mode_info
->height
- 1; y
>= 0; y
--)
424 grub_uint16_t
*iptr
= (grub_uint16_t
*) ptr
+ (mode_info
->pitch
/ 2) * y
;
426 grub_uint8_t
*optr
= buffer
;
427 for (x
= 0; x
< (int) mode_info
->width
; x
++)
429 grub_uint16_t val
= *iptr
++;
430 *optr
++ = ((val
>> bshift
) & bmask
) << mulbshift
;
431 *optr
++ = ((val
>> gshift
) & gmask
) << mulgshift
;
432 *optr
++ = ((val
>> rshift
) & rmask
) << mulrshift
;
434 grub_util_fd_write (fd
, (char *) buffer
, mode_info
->width
* 3);
443 for (y
= mode_info
->height
- 1; y
>= 0; y
--)
444 grub_util_fd_write (fd
, ((char *) ptr
+ mode_info
->pitch
* y
),
449 grub_util_fd_close (fd
);
455 grub_video_checksum_get_modename (void)
458 if (capt_mode_info
.mode_type
& GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
)
460 grub_snprintf (buf
, sizeof (buf
), "i%d", capt_mode_info
.number_of_colors
);
463 if (capt_mode_info
.red_field_pos
== 0)
465 grub_snprintf (buf
, sizeof (buf
), "bgra%d%d%d%d", capt_mode_info
.blue_mask_size
,
466 capt_mode_info
.green_mask_size
,
467 capt_mode_info
.red_mask_size
,
468 capt_mode_info
.reserved_mask_size
);
471 grub_snprintf (buf
, sizeof (buf
), "rgba%d%d%d%d", capt_mode_info
.red_mask_size
,
472 capt_mode_info
.green_mask_size
,
473 capt_mode_info
.blue_mask_size
,
474 capt_mode_info
.reserved_mask_size
);
478 #define GENERATE_MODE 1
479 //#define SAVE_ALL_IMAGES
480 //#define COLLECT_TIME_STATISTICS 1
482 #if defined (GENERATE_MODE) && defined (GRUB_MACHINE_EMU)
483 grub_util_fd_t genfd
= GRUB_UTIL_FD_INVALID
;
486 #include <grub/time.h>
491 #if defined (GRUB_MACHINE_EMU) && defined (COLLECT_TIME_STATISTICS)
493 static grub_uint64_t prev
;
495 static grub_util_fd_t tmrfd
= GRUB_UTIL_FD_INVALID
;
496 if (!GRUB_UTIL_FD_IS_VALID (tmrfd
))
497 tmrfd
= grub_util_fd_open ("time.txt", GRUB_UTIL_FD_O_WRONLY
498 | GRUB_UTIL_FD_O_CREATTRUNC
);
500 cur
= grub_util_get_cpu_time_ms ();
501 grub_snprintf (buf
, sizeof (buf
), "%s_%dx%dx%s:%d: %" PRIuGRUB_UINT64_T
" ms\n",
503 capt_mode_info
.width
,
504 capt_mode_info
.height
,
505 grub_video_checksum_get_modename (), ctr
,
508 if (GRUB_UTIL_FD_IS_VALID (tmrfd
))
509 grub_util_fd_write (tmrfd
, buf
, grub_strlen (buf
));
518 grub_uint32_t crc
= 0;
520 ptr
= grub_video_capture_get_framebuffer ();
524 #ifdef GRUB_CPU_WORDS_BIGENDIAN
525 switch (capt_mode_info
.bytes_per_pixel
)
528 crc
= grub_getcrc32c (0, ptr
, capt_mode_info
.pitch
529 * capt_mode_info
.height
);
533 unsigned x
, y
, rowskip
;
534 grub_uint8_t
*iptr
= ptr
;
536 rowskip
= capt_mode_info
.pitch
- capt_mode_info
.width
* 2;
537 for (y
= 0; y
< capt_mode_info
.height
; y
++)
539 for (x
= 0; x
< capt_mode_info
.width
; x
++)
541 crc
= grub_getcrc32c (crc
, iptr
+ 1, 1);
542 crc
= grub_getcrc32c (crc
, iptr
, 1);
545 crc
= grub_getcrc32c (crc
, iptr
, rowskip
);
552 unsigned x
, y
, rowskip
;
553 grub_uint8_t
*iptr
= ptr
;
555 rowskip
= capt_mode_info
.pitch
- capt_mode_info
.width
* 3;
556 for (y
= 0; y
< capt_mode_info
.height
; y
++)
558 for (x
= 0; x
< capt_mode_info
.width
; x
++)
560 crc
= grub_getcrc32c (crc
, iptr
+ 2, 1);
561 crc
= grub_getcrc32c (crc
, iptr
+ 1, 1);
562 crc
= grub_getcrc32c (crc
, iptr
, 1);
565 crc
= grub_getcrc32c (crc
, iptr
, rowskip
);
572 unsigned x
, y
, rowskip
;
573 grub_uint8_t
*iptr
= ptr
;
575 rowskip
= capt_mode_info
.pitch
- capt_mode_info
.width
* 4;
576 for (y
= 0; y
< capt_mode_info
.height
; y
++)
578 for (x
= 0; x
< capt_mode_info
.width
; x
++)
580 crc
= grub_getcrc32c (crc
, iptr
+ 3, 1);
581 crc
= grub_getcrc32c (crc
, iptr
+ 2, 1);
582 crc
= grub_getcrc32c (crc
, iptr
+ 1, 1);
583 crc
= grub_getcrc32c (crc
, iptr
, 1);
586 crc
= grub_getcrc32c (crc
, iptr
, rowskip
);
593 crc
= grub_getcrc32c (0, ptr
, capt_mode_info
.pitch
* capt_mode_info
.height
);
596 #if defined (GENERATE_MODE) && defined (GRUB_MACHINE_EMU)
597 if (GRUB_UTIL_FD_IS_VALID (genfd
))
600 grub_snprintf (buf
, sizeof (buf
), "0x%x, ", crc
);
601 grub_util_fd_write (genfd
, buf
, grub_strlen (buf
));
605 if (!checksums
|| ctr
>= nchk
)
607 grub_test_assert (0, "Unexpected checksum %s_%dx%dx%s:%d: 0x%x",
609 capt_mode_info
.width
,
610 capt_mode_info
.height
,
611 grub_video_checksum_get_modename (), ctr
, crc
);
613 else if (crc
!= checksums
[ctr
])
615 grub_test_assert (0, "Checksum %s_%dx%dx%s:%d failed: 0x%x vs 0x%x",
617 capt_mode_info
.width
,
618 capt_mode_info
.height
,
619 grub_video_checksum_get_modename (),
620 ctr
, crc
, checksums
[ctr
]);
622 #if !(defined (SAVE_ALL_IMAGES) && defined (GRUB_MACHINE_EMU))
630 #ifdef GRUB_MACHINE_EMU
631 char *name
= grub_xasprintf ("%s_%dx%dx%s_%d.bmp", basename
,
632 capt_mode_info
.width
,
633 capt_mode_info
.height
,
634 grub_video_checksum_get_modename (),
636 grub_video_capture_write_bmp (name
, ptr
, &capt_mode_info
);
651 unsigned number_of_colors
;
653 unsigned bytes_per_pixel
;
654 unsigned red_field_pos
;
655 unsigned red_mask_size
;
656 unsigned green_field_pos
;
657 unsigned green_mask_size
;
658 unsigned blue_field_pos
;
659 unsigned blue_mask_size
;
660 unsigned reserved_field_pos
;
661 unsigned reserved_mask_size
;
662 const grub_uint32_t
*checksums
;
666 const struct checksum_desc checksum_table
[] = {
667 #include "checksums.h"
671 grub_video_checksum (const char *basename_in
)
675 grub_video_get_info (&capt_mode_info
);
677 #if defined (GENERATE_MODE) && defined (GRUB_MACHINE_EMU)
678 if (!GRUB_UTIL_FD_IS_VALID (genfd
))
679 genfd
= grub_util_fd_open ("checksums.h", GRUB_UTIL_FD_O_WRONLY
680 | GRUB_UTIL_FD_O_CREATTRUNC
);
681 if (GRUB_UTIL_FD_IS_VALID (genfd
))
685 grub_snprintf (buf
, sizeof (buf
), "\", %d, %d, 0x%x, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d /* %dx%dx%s */, (grub_uint32_t []) { ",
686 capt_mode_info
.width
,
687 capt_mode_info
.height
,
688 capt_mode_info
.mode_type
,
689 capt_mode_info
.number_of_colors
,
691 capt_mode_info
.bytes_per_pixel
,
692 capt_mode_info
.red_field_pos
,
693 capt_mode_info
.red_mask_size
,
694 capt_mode_info
.green_field_pos
,
695 capt_mode_info
.green_mask_size
,
696 capt_mode_info
.blue_field_pos
,
697 capt_mode_info
.blue_mask_size
,
698 capt_mode_info
.reserved_field_pos
,
699 capt_mode_info
.reserved_mask_size
,
700 capt_mode_info
.width
,
701 capt_mode_info
.height
,
702 grub_video_checksum_get_modename ());
704 grub_util_fd_write (genfd
, " { \"", 5);
705 grub_util_fd_write (genfd
, basename_in
, grub_strlen (basename_in
));
706 grub_util_fd_write (genfd
, buf
, grub_strlen (buf
));
710 basename
= grub_strdup (basename_in
);
713 /* FIXME: optimize this. */
714 for (i
= 0; i
< ARRAY_SIZE (checksum_table
); i
++)
715 if (grub_strcmp (checksum_table
[i
].name
, basename_in
) == 0
716 && capt_mode_info
.width
== checksum_table
[i
].width
717 && capt_mode_info
.height
== checksum_table
[i
].height
718 && capt_mode_info
.mode_type
== checksum_table
[i
].mode_type
719 && capt_mode_info
.number_of_colors
== checksum_table
[i
].number_of_colors
720 && capt_mode_info
.bpp
== checksum_table
[i
].bpp
721 && capt_mode_info
.bytes_per_pixel
== checksum_table
[i
].bytes_per_pixel
722 && capt_mode_info
.red_field_pos
== checksum_table
[i
].red_field_pos
723 && capt_mode_info
.red_mask_size
== checksum_table
[i
].red_mask_size
724 && capt_mode_info
.green_field_pos
== checksum_table
[i
].green_field_pos
725 && capt_mode_info
.green_mask_size
== checksum_table
[i
].green_mask_size
726 && capt_mode_info
.blue_field_pos
== checksum_table
[i
].blue_field_pos
727 && capt_mode_info
.blue_mask_size
== checksum_table
[i
].blue_mask_size
728 && capt_mode_info
.reserved_field_pos
== checksum_table
[i
].reserved_field_pos
729 && capt_mode_info
.reserved_mask_size
== checksum_table
[i
].reserved_mask_size
)
731 nchk
= checksum_table
[i
].nchk
;
732 checksums
= checksum_table
[i
].checksums
;
737 grub_video_capture_refresh_cb
= checksum
;
741 grub_video_checksum_end (void)
743 #if defined (GENERATE_MODE) && defined (GRUB_MACHINE_EMU)
744 if (GRUB_UTIL_FD_IS_VALID (genfd
))
747 grub_snprintf (buf
, sizeof (buf
), "}, %d },\n", ctr
);
748 grub_util_fd_write (genfd
, buf
, grub_strlen (buf
));
751 grub_test_assert (ctr
== nchk
, "Not enough checksums %s_%dx%dx%s: %d vs %d",
753 capt_mode_info
.width
,
754 capt_mode_info
.height
,
755 grub_video_checksum_get_modename (),
757 grub_free (basename
);
762 grub_video_capture_refresh_cb
= 0;
765 static struct grub_term_output
*saved_outputs
;
766 static struct grub_term_output
*saved_gfxnext
;
767 static struct grub_term_output
*gfxterm
;
768 static int use_gfxterm
= 0;
771 grub_test_use_gfxterm (void)
773 FOR_ACTIVE_TERM_OUTPUTS (gfxterm
)
774 if (grub_strcmp (gfxterm
->name
, "gfxterm") == 0)
777 FOR_DISABLED_TERM_OUTPUTS (gfxterm
)
778 if (grub_strcmp (gfxterm
->name
, "gfxterm") == 0)
783 grub_test_assert (0, "terminal `%s' isn't found", "gfxterm");
787 if (gfxterm
->init (gfxterm
))
789 grub_test_assert (0, "terminal `%s' failed: %s", "gfxterm", grub_errmsg
);
793 saved_outputs
= grub_term_outputs
;
794 saved_gfxnext
= gfxterm
->next
;
795 grub_term_outputs
= gfxterm
;
803 grub_test_use_gfxterm_end (void)
808 gfxterm
->fini (gfxterm
);
809 gfxterm
->next
= saved_gfxnext
;
810 grub_term_outputs
= saved_outputs
;