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>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 typedef grub_err_t (*grub_video_fb_doublebuf_update_screen_t
) (void);
32 typedef volatile void *framebuf_t
;
42 struct grub_video_fbrender_target
*render_target
;
43 struct grub_video_fbrender_target
*back_target
;
44 struct grub_video_palette_data
*palette
;
47 unsigned int palette_size
;
49 struct dirty current_dirty
;
50 struct dirty previous_dirty
;
52 /* For page flipping strategy. */
53 int displayed_page
; /* The page # that is the front buffer. */
54 int render_page
; /* The page # that is the back buffer. */
55 grub_video_fb_set_page_t set_page
;
56 char *offscreen_buffer
;
57 grub_video_fb_doublebuf_update_screen_t update_screen
;
60 /* Specify "standard" VGA palette, some video cards may
61 need this and this will also be used when using RGB modes. */
62 struct grub_video_palette_data grub_video_fbstd_colors
[GRUB_VIDEO_FBSTD_NUMCOLORS
] =
65 {0x00, 0x00, 0x00, 0xFF}, // 0 = black
66 {0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
67 {0x00, 0xA8, 0x00, 0xFF}, // 2 = green
68 {0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
69 {0xA8, 0x00, 0x00, 0xFF}, // 4 = red
70 {0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
71 {0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
72 {0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
74 {0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
75 {0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
76 {0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
77 {0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
78 {0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
79 {0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
80 {0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
81 {0xFE, 0xFE, 0xFE, 0xFF} // 15 = white
85 grub_video_fb_init (void)
87 grub_free (framebuffer
.palette
);
88 framebuffer
.render_target
= 0;
89 framebuffer
.back_target
= 0;
90 framebuffer
.palette
= 0;
91 framebuffer
.palette_size
= 0;
92 framebuffer
.set_page
= 0;
97 grub_video_fb_fini (void)
99 /* TODO: destroy render targets. */
101 grub_free (framebuffer
.offscreen_buffer
);
102 grub_free (framebuffer
.palette
);
103 framebuffer
.render_target
= 0;
104 framebuffer
.back_target
= 0;
105 framebuffer
.palette
= 0;
106 framebuffer
.palette_size
= 0;
107 framebuffer
.set_page
= 0;
108 framebuffer
.offscreen_buffer
= 0;
109 return GRUB_ERR_NONE
;
113 grub_video_fb_get_info (struct grub_video_mode_info
*mode_info
)
115 /* Copy mode info from active render target. */
116 grub_memcpy (mode_info
, &framebuffer
.render_target
->mode_info
,
117 sizeof (struct grub_video_mode_info
));
119 return GRUB_ERR_NONE
;
123 grub_video_fb_get_palette (unsigned int start
, unsigned int count
,
124 struct grub_video_palette_data
*palette_data
)
128 /* Assume that we know everything from index color palette. */
129 for (i
= 0; (i
< count
) && ((i
+ start
) < framebuffer
.palette_size
); i
++)
130 palette_data
[i
] = framebuffer
.palette
[start
+ i
];
132 return GRUB_ERR_NONE
;
136 grub_video_fb_set_palette (unsigned int start
, unsigned int count
,
137 struct grub_video_palette_data
*palette_data
)
140 if (start
+ count
> framebuffer
.palette_size
)
142 framebuffer
.palette_size
= start
+ count
;
143 framebuffer
.palette
= grub_realloc (framebuffer
.palette
,
144 sizeof (framebuffer
.palette
[0])
145 * framebuffer
.palette_size
);
146 if (!framebuffer
.palette
)
148 grub_video_fb_fini ();
152 for (i
= 0; (i
< count
) && ((i
+ start
) < framebuffer
.palette_size
); i
++)
153 framebuffer
.palette
[start
+ i
] = palette_data
[i
];
154 return GRUB_ERR_NONE
;
158 grub_video_fb_set_viewport (unsigned int x
, unsigned int y
,
159 unsigned int width
, unsigned int height
)
161 /* Make sure viewport is withing screen dimensions. If viewport was set
162 to be out of the region, mark its size as zero. */
163 if (x
> framebuffer
.render_target
->mode_info
.width
)
169 if (y
> framebuffer
.render_target
->mode_info
.height
)
175 if (x
+ width
> framebuffer
.render_target
->mode_info
.width
)
176 width
= framebuffer
.render_target
->mode_info
.width
- x
;
178 if (y
+ height
> framebuffer
.render_target
->mode_info
.height
)
179 height
= framebuffer
.render_target
->mode_info
.height
- y
;
181 framebuffer
.render_target
->viewport
.x
= x
;
182 framebuffer
.render_target
->viewport
.y
= y
;
183 framebuffer
.render_target
->viewport
.width
= width
;
184 framebuffer
.render_target
->viewport
.height
= height
;
186 return GRUB_ERR_NONE
;
190 grub_video_fb_get_viewport (unsigned int *x
, unsigned int *y
,
191 unsigned int *width
, unsigned int *height
)
193 if (x
) *x
= framebuffer
.render_target
->viewport
.x
;
194 if (y
) *y
= framebuffer
.render_target
->viewport
.y
;
195 if (width
) *width
= framebuffer
.render_target
->viewport
.width
;
196 if (height
) *height
= framebuffer
.render_target
->viewport
.height
;
198 return GRUB_ERR_NONE
;
201 /* Maps color name to target optimized color format. */
203 grub_video_fb_map_color (grub_uint32_t color_name
)
205 /* TODO: implement color theme mapping code. */
207 if (color_name
< framebuffer
.palette_size
)
209 if ((framebuffer
.render_target
->mode_info
.mode_type
210 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
214 grub_video_color_t color
;
216 color
= grub_video_fb_map_rgb (framebuffer
.palette
[color_name
].r
,
217 framebuffer
.palette
[color_name
].g
,
218 framebuffer
.palette
[color_name
].b
);
227 /* Maps RGB to target optimized color format. */
229 grub_video_fb_map_rgb (grub_uint8_t red
, grub_uint8_t green
,
232 if ((framebuffer
.render_target
->mode_info
.mode_type
233 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
241 /* Find best matching color. */
242 for (i
= 0; i
< framebuffer
.palette_size
; i
++)
244 val
= framebuffer
.palette
[i
].r
- red
;
246 val
= framebuffer
.palette
[i
].g
- green
;
248 val
= framebuffer
.palette
[i
].b
- blue
;
265 else if ((framebuffer
.render_target
->mode_info
.mode_type
266 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
268 if (red
== framebuffer
.render_target
->mode_info
.fg_red
269 && green
== framebuffer
.render_target
->mode_info
.fg_green
270 && blue
== framebuffer
.render_target
->mode_info
.fg_blue
)
278 grub_uint8_t alpha
= 255; /* Opaque color. */
280 red
>>= 8 - framebuffer
.render_target
->mode_info
.red_mask_size
;
281 green
>>= 8 - framebuffer
.render_target
->mode_info
.green_mask_size
;
282 blue
>>= 8 - framebuffer
.render_target
->mode_info
.blue_mask_size
;
283 alpha
>>= 8 - framebuffer
.render_target
->mode_info
.reserved_mask_size
;
285 value
= red
<< framebuffer
.render_target
->mode_info
.red_field_pos
;
286 value
|= green
<< framebuffer
.render_target
->mode_info
.green_field_pos
;
287 value
|= blue
<< framebuffer
.render_target
->mode_info
.blue_field_pos
;
288 value
|= alpha
<< framebuffer
.render_target
->mode_info
.reserved_field_pos
;
295 /* Maps RGBA to target optimized color format. */
297 grub_video_fb_map_rgba (grub_uint8_t red
, grub_uint8_t green
,
298 grub_uint8_t blue
, grub_uint8_t alpha
)
300 if ((framebuffer
.render_target
->mode_info
.mode_type
301 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
302 /* No alpha available in index color modes, just use
303 same value as in only RGB modes. */
304 return grub_video_fb_map_rgb (red
, green
, blue
);
305 else if ((framebuffer
.render_target
->mode_info
.mode_type
306 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
308 if (red
== framebuffer
.render_target
->mode_info
.fg_red
309 && green
== framebuffer
.render_target
->mode_info
.fg_green
310 && blue
== framebuffer
.render_target
->mode_info
.fg_blue
311 && alpha
== framebuffer
.render_target
->mode_info
.fg_alpha
)
320 red
>>= 8 - framebuffer
.render_target
->mode_info
.red_mask_size
;
321 green
>>= 8 - framebuffer
.render_target
->mode_info
.green_mask_size
;
322 blue
>>= 8 - framebuffer
.render_target
->mode_info
.blue_mask_size
;
323 alpha
>>= 8 - framebuffer
.render_target
->mode_info
.reserved_mask_size
;
325 value
= red
<< framebuffer
.render_target
->mode_info
.red_field_pos
;
326 value
|= green
<< framebuffer
.render_target
->mode_info
.green_field_pos
;
327 value
|= blue
<< framebuffer
.render_target
->mode_info
.blue_field_pos
;
328 value
|= alpha
<< framebuffer
.render_target
->mode_info
.reserved_field_pos
;
334 /* Splits target optimized format to components. */
336 grub_video_fb_unmap_color (grub_video_color_t color
,
337 grub_uint8_t
*red
, grub_uint8_t
*green
,
338 grub_uint8_t
*blue
, grub_uint8_t
*alpha
)
340 struct grub_video_fbblit_info target_info
;
342 target_info
.mode_info
= &framebuffer
.render_target
->mode_info
;
343 target_info
.data
= framebuffer
.render_target
->data
;
345 grub_video_fb_unmap_color_int (&target_info
, color
, red
, green
, blue
, alpha
);
347 return GRUB_ERR_NONE
;
350 /* Splits color in source format to components. */
352 grub_video_fb_unmap_color_int (struct grub_video_fbblit_info
* source
,
353 grub_video_color_t color
,
354 grub_uint8_t
*red
, grub_uint8_t
*green
,
355 grub_uint8_t
*blue
, grub_uint8_t
*alpha
)
357 struct grub_video_mode_info
*mode_info
;
358 mode_info
= source
->mode_info
;
360 if ((mode_info
->mode_type
361 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
363 /* If we have an out-of-bounds color, return transparent black. */
373 *red
= framebuffer
.palette
[color
].r
;
374 *green
= framebuffer
.palette
[color
].g
;
375 *blue
= framebuffer
.palette
[color
].b
;
376 *alpha
= framebuffer
.palette
[color
].a
;
379 else if ((mode_info
->mode_type
380 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
384 *red
= mode_info
->fg_red
;
385 *green
= mode_info
->fg_green
;
386 *blue
= mode_info
->fg_blue
;
387 *alpha
= mode_info
->fg_alpha
;
391 *red
= mode_info
->bg_red
;
392 *green
= mode_info
->bg_green
;
393 *blue
= mode_info
->bg_blue
;
394 *alpha
= mode_info
->bg_alpha
;
401 /* Get red component. */
402 tmp
= color
>> mode_info
->red_field_pos
;
403 tmp
&= (1 << mode_info
->red_mask_size
) - 1;
404 tmp
<<= 8 - mode_info
->red_mask_size
;
405 tmp
|= (1 << (8 - mode_info
->red_mask_size
)) - 1;
408 /* Get green component. */
409 tmp
= color
>> mode_info
->green_field_pos
;
410 tmp
&= (1 << mode_info
->green_mask_size
) - 1;
411 tmp
<<= 8 - mode_info
->green_mask_size
;
412 tmp
|= (1 << (8 - mode_info
->green_mask_size
)) - 1;
415 /* Get blue component. */
416 tmp
= color
>> mode_info
->blue_field_pos
;
417 tmp
&= (1 << mode_info
->blue_mask_size
) - 1;
418 tmp
<<= 8 - mode_info
->blue_mask_size
;
419 tmp
|= (1 << (8 - mode_info
->blue_mask_size
)) - 1;
422 /* Get alpha component. */
423 if (source
->mode_info
->reserved_mask_size
> 0)
425 tmp
= color
>> mode_info
->reserved_field_pos
;
426 tmp
&= (1 << mode_info
->reserved_mask_size
) - 1;
427 tmp
<<= 8 - mode_info
->reserved_mask_size
;
428 tmp
|= (1 << (8 - mode_info
->reserved_mask_size
)) - 1;
431 /* If there is no alpha component, assume it opaque. */
439 dirty (int y
, int height
)
441 if (framebuffer
.render_target
!= framebuffer
.back_target
)
443 if (framebuffer
.current_dirty
.first_line
> y
)
444 framebuffer
.current_dirty
.first_line
= y
;
445 if (framebuffer
.current_dirty
.last_line
< y
+ height
)
446 framebuffer
.current_dirty
.last_line
= y
+ height
;
450 grub_video_fb_fill_rect (grub_video_color_t color
, int x
, int y
,
451 unsigned int width
, unsigned int height
)
453 struct grub_video_fbblit_info target
;
455 /* Make sure there is something to do. */
456 if ((x
>= (int)framebuffer
.render_target
->viewport
.width
) || (x
+ (int)width
< 0))
457 return GRUB_ERR_NONE
;
458 if ((y
>= (int)framebuffer
.render_target
->viewport
.height
) || (y
+ (int)height
< 0))
459 return GRUB_ERR_NONE
;
461 /* Do not allow drawing out of viewport. */
473 if ((x
+ width
) > framebuffer
.render_target
->viewport
.width
)
474 width
= framebuffer
.render_target
->viewport
.width
- x
;
475 if ((y
+ height
) > framebuffer
.render_target
->viewport
.height
)
476 height
= framebuffer
.render_target
->viewport
.height
- y
;
478 /* Add viewport offset. */
479 x
+= framebuffer
.render_target
->viewport
.x
;
480 y
+= framebuffer
.render_target
->viewport
.y
;
484 /* Use fbblit_info to encapsulate rendering. */
485 target
.mode_info
= &framebuffer
.render_target
->mode_info
;
486 target
.data
= framebuffer
.render_target
->data
;
488 /* Try to figure out more optimized version. Note that color is already
489 mapped to target format so we can make assumptions based on that. */
490 if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
492 grub_video_fbfill_direct32 (&target
, color
, x
, y
,
494 return GRUB_ERR_NONE
;
496 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
498 grub_video_fbfill_direct32 (&target
, color
, x
, y
,
500 return GRUB_ERR_NONE
;
502 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
504 grub_video_fbfill_direct24 (&target
, color
, x
, y
,
506 return GRUB_ERR_NONE
;
508 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_565
)
510 grub_video_fbfill_direct16 (&target
, color
, x
, y
,
512 return GRUB_ERR_NONE
;
514 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_565
)
516 grub_video_fbfill_direct16 (&target
, color
, x
, y
,
518 return GRUB_ERR_NONE
;
520 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
522 grub_video_fbfill_direct8 (&target
, color
, x
, y
,
524 return GRUB_ERR_NONE
;
527 /* No optimized version found, use default (slow) filler. */
528 grub_video_fbfill (&target
, color
, x
, y
, width
, height
);
530 return GRUB_ERR_NONE
;
533 /* NOTE: This function assumes that given coordinates are within bounds of
536 common_blitter (struct grub_video_fbblit_info
*target
,
537 struct grub_video_fbblit_info
*source
,
538 enum grub_video_blit_operators oper
, int x
, int y
,
539 unsigned int width
, unsigned int height
,
540 int offset_x
, int offset_y
)
544 if (oper
== GRUB_VIDEO_BLIT_REPLACE
)
546 /* Try to figure out more optimized version for replace operator. */
547 if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
549 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
551 grub_video_fbblit_replace_directN (target
, source
,
556 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
558 grub_video_fbblit_replace_BGRX8888_RGBX8888 (target
, source
,
563 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
565 grub_video_fbblit_replace_BGR888_RGBX8888 (target
, source
,
570 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
572 grub_video_fbblit_replace_RGB888_RGBX8888 (target
, source
,
577 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
579 grub_video_fbblit_replace_index_RGBX8888 (target
, source
,
585 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
587 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
589 grub_video_fbblit_replace_BGRX8888_RGB888 (target
, source
,
594 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
596 grub_video_fbblit_replace_RGBX8888_RGB888 (target
, source
,
601 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
603 grub_video_fbblit_replace_BGR888_RGB888 (target
, source
,
608 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
610 grub_video_fbblit_replace_directN (target
, source
,
615 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
617 grub_video_fbblit_replace_index_RGB888 (target
, source
,
623 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
625 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
627 grub_video_fbblit_replace_directN (target
, source
,
633 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
635 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
637 grub_video_fbblit_replace_directN (target
, source
,
643 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
)
645 if (target
->mode_info
->bpp
== 32)
647 grub_video_fbblit_replace_32bit_1bit (target
, source
,
652 #ifdef GRUB_HAVE_UNALIGNED_ACCESS
653 else if (target
->mode_info
->bpp
== 24)
655 grub_video_fbblit_replace_24bit_1bit (target
, source
,
661 else if (target
->mode_info
->bpp
== 16)
663 grub_video_fbblit_replace_16bit_1bit (target
, source
,
668 else if (target
->mode_info
->bpp
== 8)
670 grub_video_fbblit_replace_8bit_1bit (target
, source
,
677 /* No optimized replace operator found, use default (slow) blitter. */
678 grub_video_fbblit_replace (target
, source
, x
, y
, width
, height
,
683 /* Try to figure out more optimized blend operator. */
684 if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
686 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
688 grub_video_fbblit_blend_BGRA8888_RGBA8888 (target
, source
,
693 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
695 grub_video_fbblit_blend_RGBA8888_RGBA8888 (target
, source
,
700 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
702 grub_video_fbblit_blend_BGR888_RGBA8888 (target
, source
,
707 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
709 grub_video_fbblit_blend_RGB888_RGBA8888 (target
, source
,
714 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
716 grub_video_fbblit_blend_index_RGBA8888 (target
, source
,
722 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
724 /* Note: There is really no alpha information here, so blend is
725 changed to replace. */
727 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
729 grub_video_fbblit_replace_BGRX8888_RGB888 (target
, source
,
734 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
736 grub_video_fbblit_replace_RGBX8888_RGB888 (target
, source
,
741 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
743 grub_video_fbblit_replace_BGR888_RGB888 (target
, source
,
748 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
750 grub_video_fbblit_replace_directN (target
, source
,
755 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
757 grub_video_fbblit_replace_index_RGB888 (target
, source
,
763 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
)
765 if (target
->mode_info
->blit_format
766 == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
767 || target
->mode_info
->blit_format
768 == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
770 grub_video_fbblit_blend_XXXA8888_1bit (target
, source
,
775 #ifdef GRUB_HAVE_UNALIGNED_ACCESS
776 else if (target
->mode_info
->blit_format
777 == GRUB_VIDEO_BLIT_FORMAT_BGR_888
778 || target
->mode_info
->blit_format
779 == GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
781 grub_video_fbblit_blend_XXX888_1bit (target
, source
,
787 else if (target
->mode_info
->blit_format
788 == GRUB_VIDEO_BLIT_FORMAT_BGR_565
789 || target
->mode_info
->blit_format
790 == GRUB_VIDEO_BLIT_FORMAT_RGB_565
)
792 grub_video_fbblit_blend_XXX565_1bit (target
, source
,
801 /* No optimized blend operation found, use default (slow) blitter. */
802 grub_video_fbblit_blend (target
, source
, x
, y
, width
, height
,
808 grub_video_fb_blit_bitmap (struct grub_video_bitmap
*bitmap
,
809 enum grub_video_blit_operators oper
, int x
, int y
,
810 int offset_x
, int offset_y
,
811 unsigned int width
, unsigned int height
)
813 struct grub_video_fbblit_info source
;
814 struct grub_video_fbblit_info target
;
816 /* Make sure there is something to do. */
817 if ((width
== 0) || (height
== 0))
818 return GRUB_ERR_NONE
;
819 if ((x
>= (int)framebuffer
.render_target
->viewport
.width
) || (x
+ (int)width
< 0))
820 return GRUB_ERR_NONE
;
821 if ((y
>= (int)framebuffer
.render_target
->viewport
.height
) || (y
+ (int)height
< 0))
822 return GRUB_ERR_NONE
;
823 if ((x
+ (int)bitmap
->mode_info
.width
) < 0)
824 return GRUB_ERR_NONE
;
825 if ((y
+ (int)bitmap
->mode_info
.height
) < 0)
826 return GRUB_ERR_NONE
;
827 if ((offset_x
>= (int)bitmap
->mode_info
.width
)
828 || (offset_x
+ (int)width
< 0))
829 return GRUB_ERR_NONE
;
830 if ((offset_y
>= (int)bitmap
->mode_info
.height
)
831 || (offset_y
+ (int)height
< 0))
832 return GRUB_ERR_NONE
;
834 /* If we have negative coordinates, optimize drawing to minimum. */
863 /* Do not allow drawing out of viewport. */
864 if ((x
+ width
) > framebuffer
.render_target
->viewport
.width
)
865 width
= framebuffer
.render_target
->viewport
.width
- x
;
866 if ((y
+ height
) > framebuffer
.render_target
->viewport
.height
)
867 height
= framebuffer
.render_target
->viewport
.height
- y
;
869 if ((offset_x
+ width
) > bitmap
->mode_info
.width
)
870 width
= bitmap
->mode_info
.width
- offset_x
;
871 if ((offset_y
+ height
) > bitmap
->mode_info
.height
)
872 height
= bitmap
->mode_info
.height
- offset_y
;
874 /* Limit drawing to source render target dimensions. */
875 if (width
> bitmap
->mode_info
.width
)
876 width
= bitmap
->mode_info
.width
;
878 if (height
> bitmap
->mode_info
.height
)
879 height
= bitmap
->mode_info
.height
;
881 /* Add viewport offset. */
882 x
+= framebuffer
.render_target
->viewport
.x
;
883 y
+= framebuffer
.render_target
->viewport
.y
;
885 /* Use fbblit_info to encapsulate rendering. */
886 source
.mode_info
= &bitmap
->mode_info
;
887 source
.data
= bitmap
->data
;
888 target
.mode_info
= &framebuffer
.render_target
->mode_info
;
889 target
.data
= framebuffer
.render_target
->data
;
891 /* Do actual blitting. */
892 common_blitter (&target
, &source
, oper
, x
, y
, width
, height
,
895 return GRUB_ERR_NONE
;
899 grub_video_fb_blit_render_target (struct grub_video_fbrender_target
*source
,
900 enum grub_video_blit_operators oper
,
901 int x
, int y
, int offset_x
, int offset_y
,
902 unsigned int width
, unsigned int height
)
904 struct grub_video_fbblit_info source_info
;
905 struct grub_video_fbblit_info target_info
;
907 /* Make sure there is something to do. */
908 if ((width
== 0) || (height
== 0))
909 return GRUB_ERR_NONE
;
910 if ((x
>= (int)framebuffer
.render_target
->viewport
.width
) || (x
+ (int)width
< 0))
911 return GRUB_ERR_NONE
;
912 if ((y
>= (int)framebuffer
.render_target
->viewport
.height
) || (y
+ (int)height
< 0))
913 return GRUB_ERR_NONE
;
914 if ((x
+ (int)source
->mode_info
.width
) < 0)
915 return GRUB_ERR_NONE
;
916 if ((y
+ (int)source
->mode_info
.height
) < 0)
917 return GRUB_ERR_NONE
;
918 if ((offset_x
>= (int)source
->mode_info
.width
)
919 || (offset_x
+ (int)width
< 0))
920 return GRUB_ERR_NONE
;
921 if ((offset_y
>= (int)source
->mode_info
.height
)
922 || (offset_y
+ (int)height
< 0))
923 return GRUB_ERR_NONE
;
925 /* If we have negative coordinates, optimize drawing to minimum. */
954 /* Do not allow drawing out of viewport. */
955 if ((x
+ width
) > framebuffer
.render_target
->viewport
.width
)
956 width
= framebuffer
.render_target
->viewport
.width
- x
;
957 if ((y
+ height
) > framebuffer
.render_target
->viewport
.height
)
958 height
= framebuffer
.render_target
->viewport
.height
- y
;
960 if ((offset_x
+ width
) > source
->mode_info
.width
)
961 width
= source
->mode_info
.width
- offset_x
;
962 if ((offset_y
+ height
) > source
->mode_info
.height
)
963 height
= source
->mode_info
.height
- offset_y
;
965 /* Limit drawing to source render target dimensions. */
966 if (width
> source
->mode_info
.width
)
967 width
= source
->mode_info
.width
;
969 if (height
> source
->mode_info
.height
)
970 height
= source
->mode_info
.height
;
972 /* Add viewport offset. */
973 x
+= framebuffer
.render_target
->viewport
.x
;
974 y
+= framebuffer
.render_target
->viewport
.y
;
976 /* Use fbblit_info to encapsulate rendering. */
977 source_info
.mode_info
= &source
->mode_info
;
978 source_info
.data
= source
->data
;
979 target_info
.mode_info
= &framebuffer
.render_target
->mode_info
;
980 target_info
.data
= framebuffer
.render_target
->data
;
982 /* Do actual blitting. */
983 common_blitter (&target_info
, &source_info
, oper
, x
, y
, width
, height
,
986 return GRUB_ERR_NONE
;
990 grub_video_fb_scroll (grub_video_color_t color
, int dx
, int dy
)
999 /* 1. Check if we have something to do. */
1000 if ((dx
== 0) && (dy
== 0))
1001 return GRUB_ERR_NONE
;
1003 width
= framebuffer
.render_target
->viewport
.width
- grub_abs (dx
);
1004 height
= framebuffer
.render_target
->viewport
.height
- grub_abs (dy
);
1006 dirty (framebuffer
.render_target
->viewport
.y
,
1007 framebuffer
.render_target
->viewport
.height
);
1011 src_x
= framebuffer
.render_target
->viewport
.x
- dx
;
1012 dst_x
= framebuffer
.render_target
->viewport
.x
;
1016 src_x
= framebuffer
.render_target
->viewport
.x
;
1017 dst_x
= framebuffer
.render_target
->viewport
.x
+ dx
;
1022 src_y
= framebuffer
.render_target
->viewport
.y
- dy
;
1023 dst_y
= framebuffer
.render_target
->viewport
.y
;
1027 src_y
= framebuffer
.render_target
->viewport
.y
;
1028 dst_y
= framebuffer
.render_target
->viewport
.y
+ dy
;
1031 /* 2. Check if there is need to copy data. */
1032 if ((grub_abs (dx
) < framebuffer
.render_target
->viewport
.width
)
1033 && (grub_abs (dy
) < framebuffer
.render_target
->viewport
.height
))
1035 /* 3. Move data in render target. */
1036 struct grub_video_fbblit_info target
;
1038 int linedelta
, linelen
;
1040 target
.mode_info
= &framebuffer
.render_target
->mode_info
;
1041 target
.data
= framebuffer
.render_target
->data
;
1043 linedelta
= target
.mode_info
->pitch
1044 - width
* target
.mode_info
->bytes_per_pixel
;
1045 linelen
= width
* target
.mode_info
->bytes_per_pixel
;
1047 /* Check vertical direction of the move. */ \
1048 if (dy < 0 || (dy == 0 && dx < 0)) \
1050 dst = (void *) grub_video_fb_get_video_ptr (&target, \
1052 src = (void *) grub_video_fb_get_video_ptr (&target, \
1054 /* 3a. Move data upwards. */ \
1055 for (j = 0; j < height; j++) \
1057 for (i = 0; i < linelen; i++) \
1058 *(dst++) = *(src++); \
1065 /* 3b. Move data downwards. */ \
1066 dst = (void *) grub_video_fb_get_video_ptr (&target, \
1068 dst_y + height - 1); \
1069 src = (void *) grub_video_fb_get_video_ptr (&target, \
1071 src_y + height - 1); \
1074 for (j = 0; j < height; j++) \
1076 for (i = 0; i < linelen; i++) \
1077 *(dst--) = *(src--); \
1083 /* If everything is aligned on 32-bit use 32-bit copy. */
1084 if ((grub_addr_t
) grub_video_fb_get_video_ptr (&target
, src_x
, src_y
)
1085 % sizeof (grub_uint32_t
) == 0
1086 && (grub_addr_t
) grub_video_fb_get_video_ptr (&target
, dst_x
, dst_y
)
1087 % sizeof (grub_uint32_t
) == 0
1088 && linelen
% sizeof (grub_uint32_t
) == 0
1089 && linedelta
% sizeof (grub_uint32_t
) == 0)
1091 grub_uint32_t
*src
, *dst
;
1092 linelen
/= sizeof (grub_uint32_t
);
1093 linedelta
/= sizeof (grub_uint32_t
);
1096 /* If everything is aligned on 16-bit use 16-bit copy. */
1097 else if ((grub_addr_t
) grub_video_fb_get_video_ptr (&target
, src_x
, src_y
)
1098 % sizeof (grub_uint16_t
) == 0
1099 && (grub_addr_t
) grub_video_fb_get_video_ptr (&target
,
1101 % sizeof (grub_uint16_t
) == 0
1102 && linelen
% sizeof (grub_uint16_t
) == 0
1103 && linedelta
% sizeof (grub_uint16_t
) == 0)
1105 grub_uint16_t
*src
, *dst
;
1106 linelen
/= sizeof (grub_uint16_t
);
1107 linedelta
/= sizeof (grub_uint16_t
);
1110 /* If not aligned at all use 8-bit copy. */
1113 grub_uint8_t
*src
, *dst
;
1118 /* 4. Fill empty space with specified color. In this implementation
1119 there might be colliding areas but at the moment there is no need
1120 to optimize this. */
1122 /* 4a. Fill top & bottom parts. */
1124 grub_video_fb_fill_rect (color
, 0, 0, framebuffer
.render_target
->viewport
.width
, dy
);
1127 if (framebuffer
.render_target
->viewport
.height
< grub_abs (dy
))
1128 dy
= -framebuffer
.render_target
->viewport
.height
;
1130 grub_video_fb_fill_rect (color
, 0, framebuffer
.render_target
->viewport
.height
+ dy
,
1131 framebuffer
.render_target
->viewport
.width
, -dy
);
1134 /* 4b. Fill left & right parts. */
1136 grub_video_fb_fill_rect (color
, 0, 0,
1137 dx
, framebuffer
.render_target
->viewport
.height
);
1140 if (framebuffer
.render_target
->viewport
.width
< grub_abs (dx
))
1141 dx
= -framebuffer
.render_target
->viewport
.width
;
1143 grub_video_fb_fill_rect (color
, framebuffer
.render_target
->viewport
.width
+ dx
, 0,
1144 -dx
, framebuffer
.render_target
->viewport
.height
);
1147 return GRUB_ERR_NONE
;
1152 grub_video_fb_create_render_target (struct grub_video_fbrender_target
**result
,
1153 unsigned int width
, unsigned int height
,
1154 unsigned int mode_type
__attribute__ ((unused
)))
1156 struct grub_video_fbrender_target
*target
;
1159 /* Validate arguments. */
1163 return grub_error (GRUB_ERR_BUG
,
1164 "invalid argument given");
1166 /* Allocate memory for render target. */
1167 target
= grub_malloc (sizeof (struct grub_video_fbrender_target
));
1171 /* TODO: Implement other types too.
1172 Currently only 32bit render targets are supported. */
1174 /* Mark render target as allocated. */
1175 target
->is_allocated
= 1;
1177 /* Maximize viewport. */
1178 target
->viewport
.x
= 0;
1179 target
->viewport
.y
= 0;
1180 target
->viewport
.width
= width
;
1181 target
->viewport
.height
= height
;
1183 /* Setup render target format. */
1184 target
->mode_info
.width
= width
;
1185 target
->mode_info
.height
= height
;
1186 target
->mode_info
.mode_type
= GRUB_VIDEO_MODE_TYPE_RGB
1187 | GRUB_VIDEO_MODE_TYPE_ALPHA
;
1188 target
->mode_info
.bpp
= 32;
1189 target
->mode_info
.bytes_per_pixel
= 4;
1190 target
->mode_info
.pitch
= target
->mode_info
.bytes_per_pixel
* width
;
1191 target
->mode_info
.number_of_colors
= framebuffer
.palette_size
; /* Emulated palette. */
1192 target
->mode_info
.red_mask_size
= 8;
1193 target
->mode_info
.red_field_pos
= 0;
1194 target
->mode_info
.green_mask_size
= 8;
1195 target
->mode_info
.green_field_pos
= 8;
1196 target
->mode_info
.blue_mask_size
= 8;
1197 target
->mode_info
.blue_field_pos
= 16;
1198 target
->mode_info
.reserved_mask_size
= 8;
1199 target
->mode_info
.reserved_field_pos
= 24;
1201 target
->mode_info
.blit_format
= grub_video_get_blit_format (&target
->mode_info
);
1203 /* Calculate size needed for the data. */
1204 size
= (width
* target
->mode_info
.bytes_per_pixel
) * height
;
1206 target
->data
= grub_malloc (size
);
1213 /* Clear render target with black and maximum transparency. */
1214 grub_memset (target
->data
, 0, size
);
1216 /* TODO: Add render target to render target list. */
1218 /* Save result to caller. */
1221 return GRUB_ERR_NONE
;
1225 grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_target
**result
,
1226 const struct grub_video_mode_info
*mode_info
,
1229 struct grub_video_fbrender_target
*target
;
1232 #ifndef GRUB_HAVE_UNALIGNED_ACCESS
1233 if (!(mode_info
->bytes_per_pixel
& (mode_info
->bytes_per_pixel
- 1))
1234 && ((grub_addr_t
) ptr
& (mode_info
->bytes_per_pixel
- 1)))
1235 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "unaligned pointer");
1236 if (!(mode_info
->bytes_per_pixel
& (mode_info
->bytes_per_pixel
- 1))
1237 && (mode_info
->pitch
& (mode_info
->bytes_per_pixel
- 1)))
1238 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "unaligned pitch");
1241 /* Allocate memory for render target. */
1242 target
= grub_malloc (sizeof (struct grub_video_fbrender_target
));
1246 /* Mark framebuffer memory as non allocated. */
1247 target
->is_allocated
= 0;
1250 grub_memcpy (&(target
->mode_info
), mode_info
, sizeof (target
->mode_info
));
1252 /* Reset viewport to match new mode. */
1253 target
->viewport
.x
= 0;
1254 target
->viewport
.y
= 0;
1255 target
->viewport
.width
= mode_info
->width
;
1256 target
->viewport
.height
= mode_info
->height
;
1258 /* Clear render target with black and maximum transparency. */
1259 for (y
= 0; y
< mode_info
->height
; y
++)
1260 grub_memset (target
->data
+ mode_info
->pitch
* y
, 0,
1261 mode_info
->bytes_per_pixel
* mode_info
->width
);
1263 /* Save result to caller. */
1266 return GRUB_ERR_NONE
;
1270 grub_video_fb_delete_render_target (struct grub_video_fbrender_target
*target
)
1272 /* If there is no target, then just return without error. */
1274 return GRUB_ERR_NONE
;
1276 /* TODO: Delist render target from render target list. */
1278 /* If this is software render target, free it's memory. */
1279 if (target
->is_allocated
)
1280 grub_free (target
->data
);
1282 /* Free render target. */
1285 return GRUB_ERR_NONE
;
1289 grub_video_fb_set_active_render_target (struct grub_video_fbrender_target
*target
)
1291 if (target
== (struct grub_video_fbrender_target
*)
1292 GRUB_VIDEO_RENDER_TARGET_DISPLAY
)
1293 target
= framebuffer
.back_target
;
1296 return grub_error (GRUB_ERR_BUG
,
1297 "invalid render target given");
1299 framebuffer
.render_target
= target
;
1301 return GRUB_ERR_NONE
;
1305 grub_video_fb_get_active_render_target (struct grub_video_fbrender_target
**target
)
1307 *target
= framebuffer
.render_target
;
1309 if (*target
== framebuffer
.back_target
)
1310 *target
= (struct grub_video_fbrender_target
*) GRUB_VIDEO_RENDER_TARGET_DISPLAY
;
1312 return GRUB_ERR_NONE
;
1316 doublebuf_blit_update_screen (void)
1318 if (framebuffer
.current_dirty
.first_line
1319 <= framebuffer
.current_dirty
.last_line
)
1320 grub_memcpy ((char *) framebuffer
.pages
[0]
1321 + framebuffer
.current_dirty
.first_line
1322 * framebuffer
.back_target
->mode_info
.pitch
,
1323 (char *) framebuffer
.back_target
->data
1324 + framebuffer
.current_dirty
.first_line
1325 * framebuffer
.back_target
->mode_info
.pitch
,
1326 framebuffer
.back_target
->mode_info
.pitch
1327 * (framebuffer
.current_dirty
.last_line
1328 - framebuffer
.current_dirty
.first_line
));
1329 framebuffer
.current_dirty
.first_line
1330 = framebuffer
.back_target
->mode_info
.height
;
1331 framebuffer
.current_dirty
.last_line
= 0;
1333 return GRUB_ERR_NONE
;
1337 grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target
**back
,
1338 struct grub_video_mode_info mode_info
,
1339 volatile void *framebuf
)
1342 grub_size_t page_size
= mode_info
.pitch
* mode_info
.height
;
1344 framebuffer
.offscreen_buffer
= grub_zalloc (page_size
);
1345 if (! framebuffer
.offscreen_buffer
)
1348 err
= grub_video_fb_create_render_target_from_pointer (&framebuffer
.back_target
,
1350 framebuffer
.offscreen_buffer
);
1354 grub_free (framebuffer
.offscreen_buffer
);
1355 framebuffer
.offscreen_buffer
= 0;
1358 (*back
)->is_allocated
= 1;
1360 framebuffer
.update_screen
= doublebuf_blit_update_screen
;
1361 framebuffer
.pages
[0] = framebuf
;
1362 framebuffer
.displayed_page
= 0;
1363 framebuffer
.render_page
= 0;
1364 framebuffer
.current_dirty
.first_line
= mode_info
.height
;
1365 framebuffer
.current_dirty
.last_line
= 0;
1367 return GRUB_ERR_NONE
;
1371 doublebuf_pageflipping_update_screen (void)
1373 int new_displayed_page
;
1375 int first_line
, last_line
;
1377 first_line
= framebuffer
.current_dirty
.first_line
;
1378 last_line
= framebuffer
.current_dirty
.last_line
;
1379 if (first_line
> framebuffer
.previous_dirty
.first_line
)
1380 first_line
= framebuffer
.previous_dirty
.first_line
;
1381 if (last_line
< framebuffer
.previous_dirty
.last_line
)
1382 last_line
= framebuffer
.previous_dirty
.last_line
;
1384 if (first_line
<= last_line
)
1385 grub_memcpy ((char *) framebuffer
.pages
[framebuffer
.render_page
]
1386 + first_line
* framebuffer
.back_target
->mode_info
.pitch
,
1387 (char *) framebuffer
.back_target
->data
1388 + first_line
* framebuffer
.back_target
->mode_info
.pitch
,
1389 framebuffer
.back_target
->mode_info
.pitch
1390 * (last_line
- first_line
));
1391 framebuffer
.previous_dirty
= framebuffer
.current_dirty
;
1392 framebuffer
.current_dirty
.first_line
1393 = framebuffer
.back_target
->mode_info
.height
;
1394 framebuffer
.current_dirty
.last_line
= 0;
1396 /* Swap the page numbers in the framebuffer struct. */
1397 new_displayed_page
= framebuffer
.render_page
;
1398 framebuffer
.render_page
= framebuffer
.displayed_page
;
1399 framebuffer
.displayed_page
= new_displayed_page
;
1401 err
= framebuffer
.set_page (framebuffer
.displayed_page
);
1404 /* Restore previous state. */
1405 framebuffer
.render_page
= framebuffer
.displayed_page
;
1406 framebuffer
.displayed_page
= new_displayed_page
;
1410 return GRUB_ERR_NONE
;
1414 doublebuf_pageflipping_init (struct grub_video_mode_info
*mode_info
,
1415 volatile void *page0_ptr
,
1416 grub_video_fb_set_page_t set_page_in
,
1417 volatile void *page1_ptr
)
1420 grub_size_t page_size
= mode_info
->pitch
* mode_info
->height
;
1422 framebuffer
.offscreen_buffer
= grub_malloc (page_size
);
1423 if (! framebuffer
.offscreen_buffer
)
1428 err
= grub_video_fb_create_render_target_from_pointer (&framebuffer
.back_target
,
1430 framebuffer
.offscreen_buffer
);
1434 grub_free (framebuffer
.offscreen_buffer
);
1435 framebuffer
.offscreen_buffer
= 0;
1438 framebuffer
.back_target
->is_allocated
= 1;
1440 framebuffer
.displayed_page
= 0;
1441 framebuffer
.render_page
= 1;
1443 framebuffer
.update_screen
= doublebuf_pageflipping_update_screen
;
1444 framebuffer
.pages
[0] = page0_ptr
;
1445 framebuffer
.pages
[1] = page1_ptr
;
1447 framebuffer
.current_dirty
.first_line
1448 = framebuffer
.back_target
->mode_info
.height
;
1449 framebuffer
.current_dirty
.last_line
= 0;
1450 framebuffer
.previous_dirty
.first_line
1451 = framebuffer
.back_target
->mode_info
.height
;
1452 framebuffer
.previous_dirty
.last_line
= 0;
1454 /* Set the framebuffer memory data pointer and display the right page. */
1455 err
= set_page_in (framebuffer
.displayed_page
);
1458 grub_video_fb_delete_render_target (framebuffer
.back_target
);
1461 framebuffer
.set_page
= set_page_in
;
1463 return GRUB_ERR_NONE
;
1466 /* Select the best double buffering mode available. */
1468 grub_video_fb_setup (unsigned int mode_type
, unsigned int mode_mask
,
1469 struct grub_video_mode_info
*mode_info
,
1470 volatile void *page0_ptr
,
1471 grub_video_fb_set_page_t set_page_in
,
1472 volatile void *page1_ptr
)
1476 /* Do double buffering only if it's either requested or efficient. */
1477 if (set_page_in
&& grub_video_check_mode_flag (mode_type
, mode_mask
,
1478 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
,
1481 mode_info
->mode_type
|= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
;
1482 mode_info
->mode_type
|= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
;
1484 err
= doublebuf_pageflipping_init (mode_info
, page0_ptr
,
1489 framebuffer
.render_target
= framebuffer
.back_target
;
1490 return GRUB_ERR_NONE
;
1493 mode_info
->mode_type
&= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1494 | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
1496 grub_errno
= GRUB_ERR_NONE
;
1499 if (grub_video_check_mode_flag (mode_type
, mode_mask
,
1500 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
,
1503 /* It was much nicer with the cast directly at function call but
1504 some older gcc versions don't accept it properly.*/
1505 void *tmp
= (void *) page0_ptr
;
1506 mode_info
->mode_type
|= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1507 | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
1509 err
= grub_video_fb_doublebuf_blit_init (&framebuffer
.back_target
,
1515 framebuffer
.render_target
= framebuffer
.back_target
;
1516 return GRUB_ERR_NONE
;
1519 mode_info
->mode_type
&= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1520 | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP
);
1522 grub_errno
= GRUB_ERR_NONE
;
1525 /* Fall back to no double buffering. */
1526 err
= grub_video_fb_create_render_target_from_pointer (&framebuffer
.back_target
,
1528 (void *) page0_ptr
);
1533 framebuffer
.update_screen
= 0;
1534 framebuffer
.pages
[0] = page0_ptr
;
1535 framebuffer
.displayed_page
= 0;
1536 framebuffer
.render_page
= 0;
1537 framebuffer
.set_page
= 0;
1538 framebuffer
.current_dirty
.first_line
1539 = framebuffer
.back_target
->mode_info
.height
;
1540 framebuffer
.current_dirty
.last_line
= 0;
1542 mode_info
->mode_type
&= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
;
1544 framebuffer
.render_target
= framebuffer
.back_target
;
1546 return GRUB_ERR_NONE
;
1551 grub_video_fb_swap_buffers (void)
1554 if (!framebuffer
.update_screen
)
1555 return GRUB_ERR_NONE
;
1557 err
= framebuffer
.update_screen ();
1561 return GRUB_ERR_NONE
;
1565 grub_video_fb_get_info_and_fini (struct grub_video_mode_info
*mode_info
,
1568 grub_memcpy (mode_info
, &(framebuffer
.back_target
->mode_info
),
1569 sizeof (*mode_info
));
1571 /* We are about to load a kernel. Switch back to page zero, since some
1572 kernel drivers expect that. */
1573 if (framebuffer
.set_page
&& framebuffer
.displayed_page
!= 0)
1575 framebuffer
.update_screen ();
1578 *framebuf
= (void *) framebuffer
.pages
[framebuffer
.displayed_page
];
1580 grub_video_fb_fini ();
1582 return GRUB_ERR_NONE
;