2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2005,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/video.h>
20 #include <grub/video_fb.h>
21 #include <grub/misc.h>
23 #include <grub/fbblit.h>
24 #include <grub/fbfill.h>
25 #include <grub/fbutil.h>
26 #include <grub/bitmap.h>
30 struct grub_video_fbrender_target
*render_target
;
31 struct grub_video_fbrender_target
*front_target
;
32 struct grub_video_fbrender_target
*back_target
;
33 struct grub_video_palette_data
*palette
;
34 unsigned int palette_size
;
35 /* For page flipping strategy. */
36 int displayed_page
; /* The page # that is the front buffer. */
37 int render_page
; /* The page # that is the back buffer. */
38 grub_video_fb_set_page_t set_page
;
39 char *offscreen_buffer
;
40 grub_video_fb_doublebuf_update_screen_t update_screen
;
43 /* Specify "standard" VGA palette, some video cards may
44 need this and this will also be used when using RGB modes. */
45 struct grub_video_palette_data grub_video_fbstd_colors
[GRUB_VIDEO_FBSTD_NUMCOLORS
] =
48 {0x00, 0x00, 0x00, 0xFF}, // 0 = black
49 {0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
50 {0x00, 0xA8, 0x00, 0xFF}, // 2 = green
51 {0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
52 {0xA8, 0x00, 0x00, 0xFF}, // 4 = red
53 {0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
54 {0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
55 {0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
57 {0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
58 {0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
59 {0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
60 {0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
61 {0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
62 {0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
63 {0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
64 {0xFE, 0xFE, 0xFE, 0xFF} // 15 = white
68 grub_video_fb_init (void)
70 grub_free (framebuffer
.palette
);
71 framebuffer
.render_target
= 0;
72 framebuffer
.front_target
= 0;
73 framebuffer
.back_target
= 0;
74 framebuffer
.palette
= 0;
75 framebuffer
.palette_size
= 0;
76 framebuffer
.set_page
= 0;
81 grub_video_fb_fini (void)
83 /* TODO: destroy render targets. */
85 grub_free (framebuffer
.offscreen_buffer
);
86 grub_free (framebuffer
.palette
);
87 framebuffer
.render_target
= 0;
88 framebuffer
.front_target
= 0;
89 framebuffer
.back_target
= 0;
90 framebuffer
.palette
= 0;
91 framebuffer
.palette_size
= 0;
92 framebuffer
.set_page
= 0;
93 framebuffer
.offscreen_buffer
= 0;
98 grub_video_fb_get_info (struct grub_video_mode_info
*mode_info
)
100 /* Copy mode info from active render target. */
101 grub_memcpy (mode_info
, &framebuffer
.render_target
->mode_info
,
102 sizeof (struct grub_video_mode_info
));
104 return GRUB_ERR_NONE
;
108 grub_video_fb_get_palette (unsigned int start
, unsigned int count
,
109 struct grub_video_palette_data
*palette_data
)
113 /* Assume that we know everything from index color palette. */
114 for (i
= 0; (i
< count
) && ((i
+ start
) < framebuffer
.palette_size
); i
++)
115 palette_data
[i
] = framebuffer
.palette
[start
+ i
];
117 return GRUB_ERR_NONE
;
121 grub_video_fb_set_palette (unsigned int start
, unsigned int count
,
122 struct grub_video_palette_data
*palette_data
)
125 if (start
+ count
> framebuffer
.palette_size
)
127 framebuffer
.palette_size
= start
+ count
;
128 framebuffer
.palette
= grub_realloc (framebuffer
.palette
,
129 sizeof (framebuffer
.palette
[0])
130 * framebuffer
.palette_size
);
131 if (!framebuffer
.palette
)
133 grub_video_fb_fini ();
137 for (i
= 0; (i
< count
) && ((i
+ start
) < framebuffer
.palette_size
); i
++)
138 framebuffer
.palette
[start
+ i
] = palette_data
[i
];
139 return GRUB_ERR_NONE
;
143 grub_video_fb_set_viewport (unsigned int x
, unsigned int y
,
144 unsigned int width
, unsigned int height
)
146 /* Make sure viewport is withing screen dimensions. If viewport was set
147 to be out of the region, mark its size as zero. */
148 if (x
> framebuffer
.render_target
->mode_info
.width
)
154 if (y
> framebuffer
.render_target
->mode_info
.height
)
160 if (x
+ width
> framebuffer
.render_target
->mode_info
.width
)
161 width
= framebuffer
.render_target
->mode_info
.width
- x
;
163 if (y
+ height
> framebuffer
.render_target
->mode_info
.height
)
164 height
= framebuffer
.render_target
->mode_info
.height
- y
;
166 framebuffer
.render_target
->viewport
.x
= x
;
167 framebuffer
.render_target
->viewport
.y
= y
;
168 framebuffer
.render_target
->viewport
.width
= width
;
169 framebuffer
.render_target
->viewport
.height
= height
;
171 return GRUB_ERR_NONE
;
175 grub_video_fb_get_viewport (unsigned int *x
, unsigned int *y
,
176 unsigned int *width
, unsigned int *height
)
178 if (x
) *x
= framebuffer
.render_target
->viewport
.x
;
179 if (y
) *y
= framebuffer
.render_target
->viewport
.y
;
180 if (width
) *width
= framebuffer
.render_target
->viewport
.width
;
181 if (height
) *height
= framebuffer
.render_target
->viewport
.height
;
183 return GRUB_ERR_NONE
;
186 /* Maps color name to target optimized color format. */
188 grub_video_fb_map_color (grub_uint32_t color_name
)
190 /* TODO: implement color theme mapping code. */
192 if (color_name
< framebuffer
.palette_size
)
194 if ((framebuffer
.render_target
->mode_info
.mode_type
195 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
199 grub_video_color_t color
;
201 color
= grub_video_fb_map_rgb (framebuffer
.palette
[color_name
].r
,
202 framebuffer
.palette
[color_name
].g
,
203 framebuffer
.palette
[color_name
].b
);
212 /* Maps RGB to target optimized color format. */
214 grub_video_fb_map_rgb (grub_uint8_t red
, grub_uint8_t green
,
217 if ((framebuffer
.render_target
->mode_info
.mode_type
218 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
226 /* Find best matching color. */
227 for (i
= 0; i
< framebuffer
.palette_size
; i
++)
229 val
= framebuffer
.palette
[i
].r
- red
;
231 val
= framebuffer
.palette
[i
].g
- green
;
233 val
= framebuffer
.palette
[i
].b
- blue
;
250 else if ((framebuffer
.render_target
->mode_info
.mode_type
251 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
253 if (red
== framebuffer
.render_target
->mode_info
.fg_red
254 && green
== framebuffer
.render_target
->mode_info
.fg_green
255 && blue
== framebuffer
.render_target
->mode_info
.fg_blue
)
263 grub_uint8_t alpha
= 255; /* Opaque color. */
265 red
>>= 8 - framebuffer
.render_target
->mode_info
.red_mask_size
;
266 green
>>= 8 - framebuffer
.render_target
->mode_info
.green_mask_size
;
267 blue
>>= 8 - framebuffer
.render_target
->mode_info
.blue_mask_size
;
268 alpha
>>= 8 - framebuffer
.render_target
->mode_info
.reserved_mask_size
;
270 value
= red
<< framebuffer
.render_target
->mode_info
.red_field_pos
;
271 value
|= green
<< framebuffer
.render_target
->mode_info
.green_field_pos
;
272 value
|= blue
<< framebuffer
.render_target
->mode_info
.blue_field_pos
;
273 value
|= alpha
<< framebuffer
.render_target
->mode_info
.reserved_field_pos
;
280 /* Maps RGBA to target optimized color format. */
282 grub_video_fb_map_rgba (grub_uint8_t red
, grub_uint8_t green
,
283 grub_uint8_t blue
, grub_uint8_t alpha
)
285 if ((framebuffer
.render_target
->mode_info
.mode_type
286 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
287 /* No alpha available in index color modes, just use
288 same value as in only RGB modes. */
289 return grub_video_fb_map_rgb (red
, green
, blue
);
290 else if ((framebuffer
.render_target
->mode_info
.mode_type
291 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
293 if (red
== framebuffer
.render_target
->mode_info
.fg_red
294 && green
== framebuffer
.render_target
->mode_info
.fg_green
295 && blue
== framebuffer
.render_target
->mode_info
.fg_blue
296 && alpha
== framebuffer
.render_target
->mode_info
.fg_alpha
)
305 red
>>= 8 - framebuffer
.render_target
->mode_info
.red_mask_size
;
306 green
>>= 8 - framebuffer
.render_target
->mode_info
.green_mask_size
;
307 blue
>>= 8 - framebuffer
.render_target
->mode_info
.blue_mask_size
;
308 alpha
>>= 8 - framebuffer
.render_target
->mode_info
.reserved_mask_size
;
310 value
= red
<< framebuffer
.render_target
->mode_info
.red_field_pos
;
311 value
|= green
<< framebuffer
.render_target
->mode_info
.green_field_pos
;
312 value
|= blue
<< framebuffer
.render_target
->mode_info
.blue_field_pos
;
313 value
|= alpha
<< framebuffer
.render_target
->mode_info
.reserved_field_pos
;
319 /* Splits target optimized format to components. */
321 grub_video_fb_unmap_color (grub_video_color_t color
,
322 grub_uint8_t
*red
, grub_uint8_t
*green
,
323 grub_uint8_t
*blue
, grub_uint8_t
*alpha
)
325 struct grub_video_fbblit_info target_info
;
327 target_info
.mode_info
= &framebuffer
.render_target
->mode_info
;
328 target_info
.data
= framebuffer
.render_target
->data
;
330 grub_video_fb_unmap_color_int (&target_info
, color
, red
, green
, blue
, alpha
);
332 return GRUB_ERR_NONE
;
335 /* Splits color in source format to components. */
337 grub_video_fb_unmap_color_int (struct grub_video_fbblit_info
* source
,
338 grub_video_color_t color
,
339 grub_uint8_t
*red
, grub_uint8_t
*green
,
340 grub_uint8_t
*blue
, grub_uint8_t
*alpha
)
342 struct grub_video_mode_info
*mode_info
;
343 mode_info
= source
->mode_info
;
345 if ((mode_info
->mode_type
346 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
348 /* If we have an out-of-bounds color, return transparent black. */
358 *red
= framebuffer
.palette
[color
].r
;
359 *green
= framebuffer
.palette
[color
].g
;
360 *blue
= framebuffer
.palette
[color
].b
;
361 *alpha
= framebuffer
.palette
[color
].a
;
364 else if ((mode_info
->mode_type
365 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
369 *red
= mode_info
->fg_red
;
370 *green
= mode_info
->fg_green
;
371 *blue
= mode_info
->fg_blue
;
372 *alpha
= mode_info
->fg_alpha
;
376 *red
= mode_info
->bg_red
;
377 *green
= mode_info
->bg_green
;
378 *blue
= mode_info
->bg_blue
;
379 *alpha
= mode_info
->bg_alpha
;
386 /* Get red component. */
387 tmp
= color
>> mode_info
->red_field_pos
;
388 tmp
&= (1 << mode_info
->red_mask_size
) - 1;
389 tmp
<<= 8 - mode_info
->red_mask_size
;
390 tmp
|= (1 << (8 - mode_info
->red_mask_size
)) - 1;
393 /* Get green component. */
394 tmp
= color
>> mode_info
->green_field_pos
;
395 tmp
&= (1 << mode_info
->green_mask_size
) - 1;
396 tmp
<<= 8 - mode_info
->green_mask_size
;
397 tmp
|= (1 << (8 - mode_info
->green_mask_size
)) - 1;
400 /* Get blue component. */
401 tmp
= color
>> mode_info
->blue_field_pos
;
402 tmp
&= (1 << mode_info
->blue_mask_size
) - 1;
403 tmp
<<= 8 - mode_info
->blue_mask_size
;
404 tmp
|= (1 << (8 - mode_info
->blue_mask_size
)) - 1;
407 /* Get alpha component. */
408 if (source
->mode_info
->reserved_mask_size
> 0)
410 tmp
= color
>> mode_info
->reserved_field_pos
;
411 tmp
&= (1 << mode_info
->reserved_mask_size
) - 1;
412 tmp
<<= 8 - mode_info
->reserved_mask_size
;
413 tmp
|= (1 << (8 - mode_info
->reserved_mask_size
)) - 1;
416 /* If there is no alpha component, assume it opaque. */
424 grub_video_fb_fill_rect (grub_video_color_t color
, int x
, int y
,
425 unsigned int width
, unsigned int height
)
427 struct grub_video_fbblit_info target
;
429 /* Make sure there is something to do. */
430 if ((x
>= (int)framebuffer
.render_target
->viewport
.width
) || (x
+ (int)width
< 0))
431 return GRUB_ERR_NONE
;
432 if ((y
>= (int)framebuffer
.render_target
->viewport
.height
) || (y
+ (int)height
< 0))
433 return GRUB_ERR_NONE
;
435 /* Do not allow drawing out of viewport. */
447 if ((x
+ width
) > framebuffer
.render_target
->viewport
.width
)
448 width
= framebuffer
.render_target
->viewport
.width
- x
;
449 if ((y
+ height
) > framebuffer
.render_target
->viewport
.height
)
450 height
= framebuffer
.render_target
->viewport
.height
- y
;
452 /* Add viewport offset. */
453 x
+= framebuffer
.render_target
->viewport
.x
;
454 y
+= framebuffer
.render_target
->viewport
.y
;
456 /* Use fbblit_info to encapsulate rendering. */
457 target
.mode_info
= &framebuffer
.render_target
->mode_info
;
458 target
.data
= framebuffer
.render_target
->data
;
460 /* Try to figure out more optimized version. Note that color is already
461 mapped to target format so we can make assumptions based on that. */
462 if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
464 grub_video_fbfill_direct32 (&target
, color
, x
, y
,
466 return GRUB_ERR_NONE
;
468 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
470 grub_video_fbfill_direct32 (&target
, color
, x
, y
,
472 return GRUB_ERR_NONE
;
474 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
476 grub_video_fbfill_direct24 (&target
, color
, x
, y
,
478 return GRUB_ERR_NONE
;
480 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_565
)
482 grub_video_fbfill_direct16 (&target
, color
, x
, y
,
484 return GRUB_ERR_NONE
;
486 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_565
)
488 grub_video_fbfill_direct16 (&target
, color
, x
, y
,
490 return GRUB_ERR_NONE
;
492 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
494 grub_video_fbfill_direct8 (&target
, color
, x
, y
,
496 return GRUB_ERR_NONE
;
499 /* No optimized version found, use default (slow) filler. */
500 grub_video_fbfill (&target
, color
, x
, y
, width
, height
);
502 return GRUB_ERR_NONE
;
505 /* NOTE: This function assumes that given coordinates are within bounds of
508 common_blitter (struct grub_video_fbblit_info
*target
,
509 struct grub_video_fbblit_info
*source
,
510 enum grub_video_blit_operators oper
, int x
, int y
,
511 unsigned int width
, unsigned int height
,
512 int offset_x
, int offset_y
)
514 if (oper
== GRUB_VIDEO_BLIT_REPLACE
)
516 /* Try to figure out more optimized version for replace operator. */
517 if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
519 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
521 grub_video_fbblit_replace_directN (target
, source
,
526 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
528 grub_video_fbblit_replace_BGRX8888_RGBX8888 (target
, source
,
533 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
535 grub_video_fbblit_replace_BGR888_RGBX8888 (target
, source
,
540 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
542 grub_video_fbblit_replace_RGB888_RGBX8888 (target
, source
,
547 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
549 grub_video_fbblit_replace_index_RGBX8888 (target
, source
,
555 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
557 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
559 grub_video_fbblit_replace_BGRX8888_RGB888 (target
, source
,
564 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
566 grub_video_fbblit_replace_RGBX8888_RGB888 (target
, source
,
571 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
573 grub_video_fbblit_replace_BGR888_RGB888 (target
, source
,
578 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
580 grub_video_fbblit_replace_directN (target
, source
,
585 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
587 grub_video_fbblit_replace_index_RGB888 (target
, source
,
593 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
595 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
597 grub_video_fbblit_replace_directN (target
, source
,
603 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
605 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
607 grub_video_fbblit_replace_directN (target
, source
,
613 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
)
615 if (target
->mode_info
->bpp
== 32)
617 grub_video_fbblit_replace_32bit_1bit (target
, source
,
622 else if (target
->mode_info
->bpp
== 24)
624 grub_video_fbblit_replace_24bit_1bit (target
, source
,
629 else if (target
->mode_info
->bpp
== 16)
631 grub_video_fbblit_replace_16bit_1bit (target
, source
,
636 else if (target
->mode_info
->bpp
== 8)
638 grub_video_fbblit_replace_8bit_1bit (target
, source
,
645 /* No optimized replace operator found, use default (slow) blitter. */
646 grub_video_fbblit_replace (target
, source
, x
, y
, width
, height
,
651 /* Try to figure out more optimized blend operator. */
652 if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
654 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
656 grub_video_fbblit_blend_BGRA8888_RGBA8888 (target
, source
,
661 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
663 grub_video_fbblit_blend_RGBA8888_RGBA8888 (target
, source
,
668 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
670 grub_video_fbblit_blend_BGR888_RGBA8888 (target
, source
,
675 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
677 grub_video_fbblit_blend_RGB888_RGBA8888 (target
, source
,
682 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
684 grub_video_fbblit_blend_index_RGBA8888 (target
, source
,
690 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
692 /* Note: There is really no alpha information here, so blend is
693 changed to replace. */
695 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
697 grub_video_fbblit_replace_BGRX8888_RGB888 (target
, source
,
702 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
704 grub_video_fbblit_replace_RGBX8888_RGB888 (target
, source
,
709 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
711 grub_video_fbblit_replace_BGR888_RGB888 (target
, source
,
716 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
718 grub_video_fbblit_replace_directN (target
, source
,
723 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
725 grub_video_fbblit_replace_index_RGB888 (target
, source
,
731 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
)
733 if (target
->mode_info
->blit_format
734 == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
735 || target
->mode_info
->blit_format
736 == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
738 grub_video_fbblit_blend_XXXA8888_1bit (target
, source
,
743 else if (target
->mode_info
->blit_format
744 == GRUB_VIDEO_BLIT_FORMAT_BGR_888
745 || target
->mode_info
->blit_format
746 == GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
748 grub_video_fbblit_blend_XXX888_1bit (target
, source
,
753 else if (target
->mode_info
->blit_format
754 == GRUB_VIDEO_BLIT_FORMAT_BGR_565
755 || target
->mode_info
->blit_format
756 == GRUB_VIDEO_BLIT_FORMAT_RGB_565
)
758 grub_video_fbblit_blend_XXX565_1bit (target
, source
,
767 /* No optimized blend operation found, use default (slow) blitter. */
768 grub_video_fbblit_blend (target
, source
, x
, y
, width
, height
,
774 grub_video_fb_blit_bitmap (struct grub_video_bitmap
*bitmap
,
775 enum grub_video_blit_operators oper
, int x
, int y
,
776 int offset_x
, int offset_y
,
777 unsigned int width
, unsigned int height
)
779 struct grub_video_fbblit_info source
;
780 struct grub_video_fbblit_info target
;
782 /* Make sure there is something to do. */
783 if ((width
== 0) || (height
== 0))
784 return GRUB_ERR_NONE
;
785 if ((x
>= (int)framebuffer
.render_target
->viewport
.width
) || (x
+ (int)width
< 0))
786 return GRUB_ERR_NONE
;
787 if ((y
>= (int)framebuffer
.render_target
->viewport
.height
) || (y
+ (int)height
< 0))
788 return GRUB_ERR_NONE
;
789 if ((x
+ (int)bitmap
->mode_info
.width
) < 0)
790 return GRUB_ERR_NONE
;
791 if ((y
+ (int)bitmap
->mode_info
.height
) < 0)
792 return GRUB_ERR_NONE
;
793 if ((offset_x
>= (int)bitmap
->mode_info
.width
)
794 || (offset_x
+ (int)width
< 0))
795 return GRUB_ERR_NONE
;
796 if ((offset_y
>= (int)bitmap
->mode_info
.height
)
797 || (offset_y
+ (int)height
< 0))
798 return GRUB_ERR_NONE
;
800 /* If we have negative coordinates, optimize drawing to minimum. */
829 /* Do not allow drawing out of viewport. */
830 if ((x
+ width
) > framebuffer
.render_target
->viewport
.width
)
831 width
= framebuffer
.render_target
->viewport
.width
- x
;
832 if ((y
+ height
) > framebuffer
.render_target
->viewport
.height
)
833 height
= framebuffer
.render_target
->viewport
.height
- y
;
835 if ((offset_x
+ width
) > bitmap
->mode_info
.width
)
836 width
= bitmap
->mode_info
.width
- offset_x
;
837 if ((offset_y
+ height
) > bitmap
->mode_info
.height
)
838 height
= bitmap
->mode_info
.height
- offset_y
;
840 /* Limit drawing to source render target dimensions. */
841 if (width
> bitmap
->mode_info
.width
)
842 width
= bitmap
->mode_info
.width
;
844 if (height
> bitmap
->mode_info
.height
)
845 height
= bitmap
->mode_info
.height
;
847 /* Add viewport offset. */
848 x
+= framebuffer
.render_target
->viewport
.x
;
849 y
+= framebuffer
.render_target
->viewport
.y
;
851 /* Use fbblit_info to encapsulate rendering. */
852 source
.mode_info
= &bitmap
->mode_info
;
853 source
.data
= bitmap
->data
;
854 target
.mode_info
= &framebuffer
.render_target
->mode_info
;
855 target
.data
= framebuffer
.render_target
->data
;
857 /* Do actual blitting. */
858 common_blitter (&target
, &source
, oper
, x
, y
, width
, height
,
861 return GRUB_ERR_NONE
;
865 grub_video_fb_blit_render_target (struct grub_video_fbrender_target
*source
,
866 enum grub_video_blit_operators oper
,
867 int x
, int y
, int offset_x
, int offset_y
,
868 unsigned int width
, unsigned int height
)
870 struct grub_video_fbblit_info source_info
;
871 struct grub_video_fbblit_info target_info
;
873 /* Make sure there is something to do. */
874 if ((width
== 0) || (height
== 0))
875 return GRUB_ERR_NONE
;
876 if ((x
>= (int)framebuffer
.render_target
->viewport
.width
) || (x
+ (int)width
< 0))
877 return GRUB_ERR_NONE
;
878 if ((y
>= (int)framebuffer
.render_target
->viewport
.height
) || (y
+ (int)height
< 0))
879 return GRUB_ERR_NONE
;
880 if ((x
+ (int)source
->mode_info
.width
) < 0)
881 return GRUB_ERR_NONE
;
882 if ((y
+ (int)source
->mode_info
.height
) < 0)
883 return GRUB_ERR_NONE
;
884 if ((offset_x
>= (int)source
->mode_info
.width
)
885 || (offset_x
+ (int)width
< 0))
886 return GRUB_ERR_NONE
;
887 if ((offset_y
>= (int)source
->mode_info
.height
)
888 || (offset_y
+ (int)height
< 0))
889 return GRUB_ERR_NONE
;
891 /* If we have negative coordinates, optimize drawing to minimum. */
920 /* Do not allow drawing out of viewport. */
921 if ((x
+ width
) > framebuffer
.render_target
->viewport
.width
)
922 width
= framebuffer
.render_target
->viewport
.width
- x
;
923 if ((y
+ height
) > framebuffer
.render_target
->viewport
.height
)
924 height
= framebuffer
.render_target
->viewport
.height
- y
;
926 if ((offset_x
+ width
) > source
->mode_info
.width
)
927 width
= source
->mode_info
.width
- offset_x
;
928 if ((offset_y
+ height
) > source
->mode_info
.height
)
929 height
= source
->mode_info
.height
- offset_y
;
931 /* Limit drawing to source render target dimensions. */
932 if (width
> source
->mode_info
.width
)
933 width
= source
->mode_info
.width
;
935 if (height
> source
->mode_info
.height
)
936 height
= source
->mode_info
.height
;
938 /* Add viewport offset. */
939 x
+= framebuffer
.render_target
->viewport
.x
;
940 y
+= framebuffer
.render_target
->viewport
.y
;
942 /* Use fbblit_info to encapsulate rendering. */
943 source_info
.mode_info
= &source
->mode_info
;
944 source_info
.data
= source
->data
;
945 target_info
.mode_info
= &framebuffer
.render_target
->mode_info
;
946 target_info
.data
= framebuffer
.render_target
->data
;
948 /* Do actual blitting. */
949 common_blitter (&target_info
, &source_info
, oper
, x
, y
, width
, height
,
952 return GRUB_ERR_NONE
;
956 grub_video_fb_scroll (grub_video_color_t color
, int dx
, int dy
)
965 /* 1. Check if we have something to do. */
966 if ((dx
== 0) && (dy
== 0))
967 return GRUB_ERR_NONE
;
969 width
= framebuffer
.render_target
->viewport
.width
- grub_abs (dx
);
970 height
= framebuffer
.render_target
->viewport
.height
- grub_abs (dy
);
974 src_x
= framebuffer
.render_target
->viewport
.x
- dx
;
975 dst_x
= framebuffer
.render_target
->viewport
.x
;
979 src_x
= framebuffer
.render_target
->viewport
.x
;
980 dst_x
= framebuffer
.render_target
->viewport
.x
+ dx
;
985 src_y
= framebuffer
.render_target
->viewport
.y
- dy
;
986 dst_y
= framebuffer
.render_target
->viewport
.y
;
990 src_y
= framebuffer
.render_target
->viewport
.y
;
991 dst_y
= framebuffer
.render_target
->viewport
.y
+ dy
;
994 /* 2. Check if there is need to copy data. */
995 if ((grub_abs (dx
) < framebuffer
.render_target
->viewport
.width
)
996 && (grub_abs (dy
) < framebuffer
.render_target
->viewport
.height
))
998 /* 3. Move data in render target. */
999 struct grub_video_fbblit_info target
;
1001 int linedelta
, linelen
;
1003 target
.mode_info
= &framebuffer
.render_target
->mode_info
;
1004 target
.data
= framebuffer
.render_target
->data
;
1006 linedelta
= target
.mode_info
->pitch
1007 - width
* target
.mode_info
->bytes_per_pixel
;
1008 linelen
= width
* target
.mode_info
->bytes_per_pixel
;
1010 /* Check vertical direction of the move. */ \
1011 if (dy < 0 || (dy == 0 && dx < 0)) \
1013 dst = (void *) grub_video_fb_get_video_ptr (&target, \
1015 src = (void *) grub_video_fb_get_video_ptr (&target, \
1017 /* 3a. Move data upwards. */ \
1018 for (j = 0; j < height; j++) \
1020 for (i = 0; i < linelen; i++) \
1021 *(dst++) = *(src++); \
1028 /* 3b. Move data downwards. */ \
1029 dst = (void *) grub_video_fb_get_video_ptr (&target, \
1031 dst_y + height - 1); \
1032 src = (void *) grub_video_fb_get_video_ptr (&target, \
1034 src_y + height - 1); \
1037 for (j = 0; j < height; j++) \
1039 for (i = 0; i < linelen; i++) \
1040 *(dst--) = *(src--); \
1046 /* If everything is aligned on 32-bit use 32-bit copy. */
1047 if ((grub_addr_t
) grub_video_fb_get_video_ptr (&target
, src_x
, src_y
)
1048 % sizeof (grub_uint32_t
) == 0
1049 && (grub_addr_t
) grub_video_fb_get_video_ptr (&target
, dst_x
, dst_y
)
1050 % sizeof (grub_uint32_t
) == 0
1051 && linelen
% sizeof (grub_uint32_t
) == 0
1052 && linedelta
% sizeof (grub_uint32_t
) == 0)
1054 grub_uint32_t
*src
, *dst
;
1055 linelen
/= sizeof (grub_uint32_t
);
1056 linedelta
/= sizeof (grub_uint32_t
);
1059 /* If everything is aligned on 16-bit use 16-bit copy. */
1060 else if ((grub_addr_t
) grub_video_fb_get_video_ptr (&target
, src_x
, src_y
)
1061 % sizeof (grub_uint16_t
) == 0
1062 && (grub_addr_t
) grub_video_fb_get_video_ptr (&target
,
1064 % sizeof (grub_uint16_t
) == 0
1065 && linelen
% sizeof (grub_uint16_t
) == 0
1066 && linedelta
% sizeof (grub_uint16_t
) == 0)
1068 grub_uint16_t
*src
, *dst
;
1069 linelen
/= sizeof (grub_uint16_t
);
1070 linedelta
/= sizeof (grub_uint16_t
);
1073 /* If not aligned at all use 8-bit copy. */
1076 grub_uint8_t
*src
, *dst
;
1081 /* 4. Fill empty space with specified color. In this implementation
1082 there might be colliding areas but at the moment there is no need
1083 to optimize this. */
1085 /* 4a. Fill top & bottom parts. */
1087 grub_video_fb_fill_rect (color
, 0, 0, framebuffer
.render_target
->viewport
.width
, dy
);
1090 if (framebuffer
.render_target
->viewport
.height
< grub_abs (dy
))
1091 dy
= -framebuffer
.render_target
->viewport
.height
;
1093 grub_video_fb_fill_rect (color
, 0, framebuffer
.render_target
->viewport
.height
+ dy
,
1094 framebuffer
.render_target
->viewport
.width
, -dy
);
1097 /* 4b. Fill left & right parts. */
1099 grub_video_fb_fill_rect (color
, 0, 0,
1100 dx
, framebuffer
.render_target
->viewport
.height
);
1103 if (framebuffer
.render_target
->viewport
.width
< grub_abs (dx
))
1104 dx
= -framebuffer
.render_target
->viewport
.width
;
1106 grub_video_fb_fill_rect (color
, framebuffer
.render_target
->viewport
.width
+ dx
, 0,
1107 -dx
, framebuffer
.render_target
->viewport
.height
);
1110 return GRUB_ERR_NONE
;
1115 grub_video_fb_create_render_target (struct grub_video_fbrender_target
**result
,
1116 unsigned int width
, unsigned int height
,
1117 unsigned int mode_type
__attribute__ ((unused
)))
1119 struct grub_video_fbrender_target
*target
;
1122 /* Validate arguments. */
1126 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
1127 "invalid argument given");
1129 /* Allocate memory for render target. */
1130 target
= grub_malloc (sizeof (struct grub_video_fbrender_target
));
1134 /* TODO: Implement other types too.
1135 Currently only 32bit render targets are supported. */
1137 /* Mark render target as allocated. */
1138 target
->is_allocated
= 1;
1140 /* Maximize viewport. */
1141 target
->viewport
.x
= 0;
1142 target
->viewport
.y
= 0;
1143 target
->viewport
.width
= width
;
1144 target
->viewport
.height
= height
;
1146 /* Setup render target format. */
1147 target
->mode_info
.width
= width
;
1148 target
->mode_info
.height
= height
;
1149 target
->mode_info
.mode_type
= GRUB_VIDEO_MODE_TYPE_RGB
1150 | GRUB_VIDEO_MODE_TYPE_ALPHA
;
1151 target
->mode_info
.bpp
= 32;
1152 target
->mode_info
.bytes_per_pixel
= 4;
1153 target
->mode_info
.pitch
= target
->mode_info
.bytes_per_pixel
* width
;
1154 target
->mode_info
.number_of_colors
= framebuffer
.palette_size
; /* Emulated palette. */
1155 target
->mode_info
.red_mask_size
= 8;
1156 target
->mode_info
.red_field_pos
= 0;
1157 target
->mode_info
.green_mask_size
= 8;
1158 target
->mode_info
.green_field_pos
= 8;
1159 target
->mode_info
.blue_mask_size
= 8;
1160 target
->mode_info
.blue_field_pos
= 16;
1161 target
->mode_info
.reserved_mask_size
= 8;
1162 target
->mode_info
.reserved_field_pos
= 24;
1164 target
->mode_info
.blit_format
= grub_video_get_blit_format (&target
->mode_info
);
1166 /* Calculate size needed for the data. */
1167 size
= (width
* target
->mode_info
.bytes_per_pixel
) * height
;
1169 target
->data
= grub_malloc (size
);
1176 /* Clear render target with black and maximum transparency. */
1177 grub_memset (target
->data
, 0, size
);
1179 /* TODO: Add render target to render target list. */
1181 /* Save result to caller. */
1184 return GRUB_ERR_NONE
;
1188 grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_target
**result
,
1189 const struct grub_video_mode_info
*mode_info
,
1192 struct grub_video_fbrender_target
*target
;
1195 /* Allocate memory for render target. */
1196 target
= grub_malloc (sizeof (struct grub_video_fbrender_target
));
1200 /* Mark framebuffer memory as non allocated. */
1201 target
->is_allocated
= 0;
1204 grub_memcpy (&(target
->mode_info
), mode_info
, sizeof (target
->mode_info
));
1206 /* Reset viewport to match new mode. */
1207 target
->viewport
.x
= 0;
1208 target
->viewport
.y
= 0;
1209 target
->viewport
.width
= mode_info
->width
;
1210 target
->viewport
.height
= mode_info
->height
;
1212 /* Clear render target with black and maximum transparency. */
1213 for (y
= 0; y
< mode_info
->height
; y
++)
1214 grub_memset (target
->data
+ mode_info
->pitch
* y
, 0,
1215 mode_info
->bytes_per_pixel
* mode_info
->width
);
1217 /* Save result to caller. */
1220 return GRUB_ERR_NONE
;
1224 grub_video_fb_delete_render_target (struct grub_video_fbrender_target
*target
)
1226 /* If there is no target, then just return without error. */
1228 return GRUB_ERR_NONE
;
1230 /* TODO: Delist render target from render target list. */
1232 /* If this is software render target, free it's memory. */
1233 if (target
->is_allocated
)
1234 grub_free (target
->data
);
1236 /* Free render target. */
1239 return GRUB_ERR_NONE
;
1243 grub_video_fb_set_active_render_target (struct grub_video_fbrender_target
*target
)
1245 if (target
== (struct grub_video_fbrender_target
*)
1246 GRUB_VIDEO_RENDER_TARGET_DISPLAY
)
1247 target
= framebuffer
.back_target
;
1250 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
1251 "invalid render target given");
1253 framebuffer
.render_target
= target
;
1255 return GRUB_ERR_NONE
;
1259 grub_video_fb_get_active_render_target (struct grub_video_fbrender_target
**target
)
1261 *target
= framebuffer
.render_target
;
1263 if (*target
== framebuffer
.back_target
)
1264 *target
= (struct grub_video_fbrender_target
*) GRUB_VIDEO_RENDER_TARGET_DISPLAY
;
1266 return GRUB_ERR_NONE
;
1270 doublebuf_blit_update_screen (struct grub_video_fbrender_target
*front
,
1271 struct grub_video_fbrender_target
*back
)
1273 grub_memcpy (front
->data
, back
->data
,
1274 front
->mode_info
.pitch
* front
->mode_info
.height
);
1275 return GRUB_ERR_NONE
;
1279 grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target
**front
,
1280 struct grub_video_fbrender_target
**back
,
1281 struct grub_video_mode_info mode_info
,
1285 int page_size
= mode_info
.pitch
* mode_info
.height
;
1287 err
= grub_video_fb_create_render_target_from_pointer (front
, &mode_info
,
1292 framebuffer
.offscreen_buffer
= grub_malloc (page_size
);
1293 if (! framebuffer
.offscreen_buffer
)
1295 grub_video_fb_delete_render_target (*front
);
1300 err
= grub_video_fb_create_render_target_from_pointer (back
, &mode_info
,
1301 framebuffer
.offscreen_buffer
);
1305 grub_video_fb_delete_render_target (*front
);
1306 grub_free (framebuffer
.offscreen_buffer
);
1307 framebuffer
.offscreen_buffer
= 0;
1311 (*back
)->is_allocated
= 1;
1313 framebuffer
.update_screen
= doublebuf_blit_update_screen
;
1315 return GRUB_ERR_NONE
;
1319 doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target
*front
1320 __attribute__ ((unused
)),
1321 struct grub_video_fbrender_target
*back
1322 __attribute__ ((unused
)))
1324 int new_displayed_page
;
1325 struct grub_video_fbrender_target
*target
;
1328 /* Swap the page numbers in the framebuffer struct. */
1329 new_displayed_page
= framebuffer
.render_page
;
1330 framebuffer
.render_page
= framebuffer
.displayed_page
;
1331 framebuffer
.displayed_page
= new_displayed_page
;
1333 err
= framebuffer
.set_page (framebuffer
.displayed_page
);
1336 /* Restore previous state. */
1337 framebuffer
.render_page
= framebuffer
.displayed_page
;
1338 framebuffer
.displayed_page
= new_displayed_page
;
1342 target
= framebuffer
.back_target
;
1343 framebuffer
.back_target
= framebuffer
.front_target
;
1344 framebuffer
.front_target
= target
;
1346 if (framebuffer
.front_target
->mode_info
.mode_type
1347 & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
)
1348 grub_memcpy (framebuffer
.back_target
->data
, framebuffer
.front_target
->data
,
1349 framebuffer
.back_target
->mode_info
.pitch
1350 * framebuffer
.back_target
->mode_info
.height
);
1352 err
= grub_video_fb_get_active_render_target (&target
);
1356 if (framebuffer
.render_target
== framebuffer
.back_target
)
1357 framebuffer
.render_target
= framebuffer
.front_target
;
1358 else if (framebuffer
.render_target
== framebuffer
.front_target
)
1359 framebuffer
.render_target
= framebuffer
.back_target
;
1365 doublebuf_pageflipping_init (struct grub_video_mode_info
*mode_info
,
1366 volatile void *page0_ptr
,
1367 grub_video_fb_set_page_t set_page_in
,
1368 volatile void *page1_ptr
)
1372 framebuffer
.displayed_page
= 0;
1373 framebuffer
.render_page
= 1;
1375 framebuffer
.update_screen
= doublebuf_pageflipping_update_screen
;
1377 err
= grub_video_fb_create_render_target_from_pointer (&framebuffer
.front_target
,
1379 (void *) page0_ptr
);
1383 err
= grub_video_fb_create_render_target_from_pointer (&framebuffer
.back_target
,
1385 (void *) page1_ptr
);
1388 grub_video_fb_delete_render_target (framebuffer
.front_target
);
1392 /* Set the framebuffer memory data pointer and display the right page. */
1393 err
= set_page_in (framebuffer
.displayed_page
);
1396 grub_video_fb_delete_render_target (framebuffer
.front_target
);
1397 grub_video_fb_delete_render_target (framebuffer
.back_target
);
1400 framebuffer
.set_page
= set_page_in
;
1402 return GRUB_ERR_NONE
;
1405 /* Select the best double buffering mode available. */
1407 grub_video_fb_setup (unsigned int mode_type
, unsigned int mode_mask
,
1408 struct grub_video_mode_info
*mode_info
,
1409 volatile void *page0_ptr
,
1410 grub_video_fb_set_page_t set_page_in
,
1411 volatile void *page1_ptr
)
1414 int updating_swap_needed
;
1416 updating_swap_needed
1417 = grub_video_check_mode_flag (mode_type
, mode_mask
,
1418 GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
, 0);
1420 /* Do double buffering only if it's either requested or efficient. */
1421 if (set_page_in
&& grub_video_check_mode_flag (mode_type
, mode_mask
,
1422 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
,
1423 !updating_swap_needed
))
1425 mode_info
->mode_type
|= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
;
1426 if (updating_swap_needed
)
1427 mode_info
->mode_type
|= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
;
1429 err
= doublebuf_pageflipping_init (mode_info
, page0_ptr
,
1434 framebuffer
.render_target
= framebuffer
.back_target
;
1435 return GRUB_ERR_NONE
;
1438 mode_info
->mode_type
&= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1439 | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
1441 grub_errno
= GRUB_ERR_NONE
;
1444 if (grub_video_check_mode_flag (mode_type
, mode_mask
,
1445 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
,
1448 mode_info
->mode_type
|= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1449 | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
1451 err
= grub_video_fb_doublebuf_blit_init (&framebuffer
.front_target
,
1452 &framebuffer
.back_target
,
1454 (void *) page0_ptr
);
1458 framebuffer
.render_target
= framebuffer
.back_target
;
1459 return GRUB_ERR_NONE
;
1462 mode_info
->mode_type
&= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1463 | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
1465 grub_errno
= GRUB_ERR_NONE
;
1468 /* Fall back to no double buffering. */
1469 err
= grub_video_fb_create_render_target_from_pointer (&framebuffer
.front_target
,
1471 (void *) page0_ptr
);
1476 framebuffer
.back_target
= framebuffer
.front_target
;
1477 framebuffer
.update_screen
= 0;
1479 mode_info
->mode_type
&= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
;
1481 framebuffer
.render_target
= framebuffer
.back_target
;
1483 return GRUB_ERR_NONE
;
1488 grub_video_fb_swap_buffers (void)
1491 if (!framebuffer
.update_screen
)
1492 return GRUB_ERR_NONE
;
1494 err
= framebuffer
.update_screen (framebuffer
.front_target
,
1495 framebuffer
.back_target
);
1499 return GRUB_ERR_NONE
;
1503 grub_video_fb_get_info_and_fini (struct grub_video_mode_info
*mode_info
,
1506 grub_memcpy (mode_info
, &(framebuffer
.front_target
->mode_info
),
1507 sizeof (*mode_info
));
1508 *framebuf
= framebuffer
.front_target
->data
;
1510 grub_video_fb_fini ();
1512 return GRUB_ERR_NONE
;