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>
28 static struct grub_video_fbrender_target
*render_target
;
29 struct grub_video_palette_data
*palette
;
30 static unsigned int palette_size
;
32 /* Specify "standard" VGA palette, some video cards may
33 need this and this will also be used when using RGB modes. */
34 struct grub_video_palette_data grub_video_fbstd_colors
[16] =
37 {0x00, 0x00, 0x00, 0xFF}, // 0 = black
38 {0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
39 {0x00, 0xA8, 0x00, 0xFF}, // 2 = green
40 {0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
41 {0xA8, 0x00, 0x00, 0xFF}, // 4 = red
42 {0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
43 {0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
44 {0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
46 {0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
47 {0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
48 {0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
49 {0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
50 {0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
51 {0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
52 {0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
53 {0xFE, 0xFE, 0xFE, 0xFF} // 15 = white
57 grub_video_fb_init (void)
67 grub_video_fb_fini (void)
77 grub_video_fb_get_info (struct grub_video_mode_info
*mode_info
)
79 /* Copy mode info from active render target. */
80 grub_memcpy (mode_info
, &render_target
->mode_info
,
81 sizeof (struct grub_video_mode_info
));
88 grub_video_fb_get_video_ptr (struct grub_video_fbblit_info
*source
,
89 grub_uint32_t x
, grub_uint32_t y
)
91 grub_uint8_t
*ptr
= 0;
93 switch (source
->mode_info
->bpp
)
96 ptr
= (grub_uint8_t
*)source
->data
97 + y
* source
->mode_info
->pitch
102 ptr
= (grub_uint8_t
*)source
->data
103 + y
* source
->mode_info
->pitch
109 ptr
= (grub_uint8_t
*)source
->data
110 + y
* source
->mode_info
->pitch
115 ptr
= (grub_uint8_t
*)source
->data
116 + y
* source
->mode_info
->pitch
125 grub_video_fb_get_palette (unsigned int start
, unsigned int count
,
126 struct grub_video_palette_data
*palette_data
)
130 /* Assume that we know everything from index color palette. */
131 for (i
= 0; (i
< count
) && ((i
+ start
) < palette_size
); i
++)
132 palette_data
[i
] = palette
[start
+ i
];
134 return GRUB_ERR_NONE
;
138 grub_video_fb_set_palette (unsigned int start
, unsigned int count
,
139 struct grub_video_palette_data
*palette_data
)
142 if (start
+ count
> palette_size
)
144 palette_size
= start
+ count
;
145 palette
= grub_realloc (palette
, sizeof (palette
[0]) * palette_size
);
148 grub_video_fb_fini ();
152 for (i
= 0; (i
< count
) && ((i
+ start
) < palette_size
); i
++)
153 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 render_target
->viewport
.x
= x
;
162 render_target
->viewport
.y
= y
;
163 render_target
->viewport
.width
= width
;
164 render_target
->viewport
.height
= height
;
166 return GRUB_ERR_NONE
;
170 grub_video_fb_get_viewport (unsigned int *x
, unsigned int *y
,
171 unsigned int *width
, unsigned int *height
)
173 if (x
) *x
= render_target
->viewport
.x
;
174 if (y
) *y
= render_target
->viewport
.y
;
175 if (width
) *width
= render_target
->viewport
.width
;
176 if (height
) *height
= render_target
->viewport
.height
;
178 return GRUB_ERR_NONE
;
181 /* Maps color name to target optimized color format. */
183 grub_video_fb_map_color (grub_uint32_t color_name
)
185 /* TODO: implement color theme mapping code. */
187 if (color_name
< palette_size
)
189 if ((render_target
->mode_info
.mode_type
190 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
194 grub_video_color_t color
;
196 color
= grub_video_fb_map_rgb (palette
[color_name
].r
,
197 palette
[color_name
].g
,
198 palette
[color_name
].b
);
207 /* Maps RGB to target optimized color format. */
209 grub_video_fb_map_rgb (grub_uint8_t red
, grub_uint8_t green
,
212 if ((render_target
->mode_info
.mode_type
213 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
221 /* Find best matching color. */
222 for (i
= 0; i
< palette_size
; i
++)
224 val
= palette
[i
].r
- red
;
226 val
= palette
[i
].g
- green
;
228 val
= palette
[i
].b
- blue
;
245 else if ((render_target
->mode_info
.mode_type
246 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
248 if (red
== render_target
->mode_info
.fg_red
249 && green
== render_target
->mode_info
.fg_green
250 && blue
== render_target
->mode_info
.fg_blue
)
258 grub_uint8_t alpha
= 255; /* Opaque color. */
260 red
>>= 8 - render_target
->mode_info
.red_mask_size
;
261 green
>>= 8 - render_target
->mode_info
.green_mask_size
;
262 blue
>>= 8 - render_target
->mode_info
.blue_mask_size
;
263 alpha
>>= 8 - render_target
->mode_info
.reserved_mask_size
;
265 value
= red
<< render_target
->mode_info
.red_field_pos
;
266 value
|= green
<< render_target
->mode_info
.green_field_pos
;
267 value
|= blue
<< render_target
->mode_info
.blue_field_pos
;
268 value
|= alpha
<< render_target
->mode_info
.reserved_field_pos
;
275 /* Maps RGBA to target optimized color format. */
277 grub_video_fb_map_rgba (grub_uint8_t red
, grub_uint8_t green
,
278 grub_uint8_t blue
, grub_uint8_t alpha
)
280 if ((render_target
->mode_info
.mode_type
281 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
282 /* No alpha available in index color modes, just use
283 same value as in only RGB modes. */
284 return grub_video_fb_map_rgb (red
, green
, blue
);
285 else if ((render_target
->mode_info
.mode_type
286 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
288 if (red
== render_target
->mode_info
.fg_red
289 && green
== render_target
->mode_info
.fg_green
290 && blue
== render_target
->mode_info
.fg_blue
291 && alpha
== render_target
->mode_info
.fg_alpha
)
300 red
>>= 8 - render_target
->mode_info
.red_mask_size
;
301 green
>>= 8 - render_target
->mode_info
.green_mask_size
;
302 blue
>>= 8 - render_target
->mode_info
.blue_mask_size
;
303 alpha
>>= 8 - render_target
->mode_info
.reserved_mask_size
;
305 value
= red
<< render_target
->mode_info
.red_field_pos
;
306 value
|= green
<< render_target
->mode_info
.green_field_pos
;
307 value
|= blue
<< render_target
->mode_info
.blue_field_pos
;
308 value
|= alpha
<< render_target
->mode_info
.reserved_field_pos
;
314 /* Splits target optimized format to components. */
316 grub_video_fb_unmap_color (grub_video_color_t color
,
317 grub_uint8_t
*red
, grub_uint8_t
*green
,
318 grub_uint8_t
*blue
, grub_uint8_t
*alpha
)
320 struct grub_video_fbblit_info target_info
;
322 target_info
.mode_info
= &render_target
->mode_info
;
323 target_info
.data
= render_target
->data
;
325 grub_video_fb_unmap_color_int (&target_info
, color
, red
, green
, blue
, alpha
);
327 return GRUB_ERR_NONE
;
330 /* Splits color in source format to components. */
332 grub_video_fb_unmap_color_int (struct grub_video_fbblit_info
* source
,
333 grub_video_color_t color
,
334 grub_uint8_t
*red
, grub_uint8_t
*green
,
335 grub_uint8_t
*blue
, grub_uint8_t
*alpha
)
337 struct grub_video_mode_info
*mode_info
;
338 mode_info
= source
->mode_info
;
340 if ((mode_info
->mode_type
341 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
) != 0)
343 /* If we have an out-of-bounds color, return transparent black. */
353 *red
= palette
[color
].r
;
354 *green
= palette
[color
].g
;
355 *blue
= palette
[color
].b
;
356 *alpha
= palette
[color
].a
;
359 else if ((mode_info
->mode_type
360 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
) != 0)
364 *red
= mode_info
->fg_red
;
365 *green
= mode_info
->fg_green
;
366 *blue
= mode_info
->fg_blue
;
367 *alpha
= mode_info
->fg_alpha
;
371 *red
= mode_info
->bg_red
;
372 *green
= mode_info
->bg_green
;
373 *blue
= mode_info
->bg_blue
;
374 *alpha
= mode_info
->bg_alpha
;
381 /* Get red component. */
382 tmp
= color
>> mode_info
->red_field_pos
;
383 tmp
&= (1 << mode_info
->red_mask_size
) - 1;
384 tmp
<<= 8 - mode_info
->red_mask_size
;
385 tmp
|= (1 << (8 - mode_info
->red_mask_size
)) - 1;
388 /* Get green component. */
389 tmp
= color
>> mode_info
->green_field_pos
;
390 tmp
&= (1 << mode_info
->green_mask_size
) - 1;
391 tmp
<<= 8 - mode_info
->green_mask_size
;
392 tmp
|= (1 << (8 - mode_info
->green_mask_size
)) - 1;
395 /* Get blue component. */
396 tmp
= color
>> mode_info
->blue_field_pos
;
397 tmp
&= (1 << mode_info
->blue_mask_size
) - 1;
398 tmp
<<= 8 - mode_info
->blue_mask_size
;
399 tmp
|= (1 << (8 - mode_info
->blue_mask_size
)) - 1;
402 /* Get alpha component. */
403 if (source
->mode_info
->reserved_mask_size
> 0)
405 tmp
= color
>> mode_info
->reserved_field_pos
;
406 tmp
&= (1 << mode_info
->reserved_mask_size
) - 1;
407 tmp
<<= 8 - mode_info
->reserved_mask_size
;
408 tmp
|= (1 << (8 - mode_info
->reserved_mask_size
)) - 1;
411 /* If there is no alpha component, assume it opaque. */
419 grub_video_fb_fill_rect (grub_video_color_t color
, int x
, int y
,
420 unsigned int width
, unsigned int height
)
422 struct grub_video_fbblit_info target
;
424 /* Make sure there is something to do. */
425 if ((x
>= (int)render_target
->viewport
.width
) || (x
+ (int)width
< 0))
426 return GRUB_ERR_NONE
;
427 if ((y
>= (int)render_target
->viewport
.height
) || (y
+ (int)height
< 0))
428 return GRUB_ERR_NONE
;
430 /* Do not allow drawing out of viewport. */
442 if ((x
+ width
) > render_target
->viewport
.width
)
443 width
= render_target
->viewport
.width
- x
;
444 if ((y
+ height
) > render_target
->viewport
.height
)
445 height
= render_target
->viewport
.height
- y
;
447 /* Add viewport offset. */
448 x
+= render_target
->viewport
.x
;
449 y
+= render_target
->viewport
.y
;
451 /* Use fbblit_info to encapsulate rendering. */
452 target
.mode_info
= &render_target
->mode_info
;
453 target
.data
= render_target
->data
;
455 /* Try to figure out more optimized version. Note that color is already
456 mapped to target format so we can make assumptions based on that. */
457 if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
459 grub_video_fbfill_direct32 (&target
, color
, x
, y
,
461 return GRUB_ERR_NONE
;
463 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
465 grub_video_fbfill_direct32 (&target
, color
, x
, y
,
467 return GRUB_ERR_NONE
;
469 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
471 grub_video_fbfill_direct24 (&target
, color
, x
, y
,
473 return GRUB_ERR_NONE
;
475 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_565
)
477 grub_video_fbfill_direct16 (&target
, color
, x
, y
,
479 return GRUB_ERR_NONE
;
481 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_565
)
483 grub_video_fbfill_direct16 (&target
, color
, x
, y
,
485 return GRUB_ERR_NONE
;
487 else if (target
.mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
489 grub_video_fbfill_direct8 (&target
, color
, x
, y
,
491 return GRUB_ERR_NONE
;
494 /* No optimized version found, use default (slow) filler. */
495 grub_video_fbfill (&target
, color
, x
, y
, width
, height
);
497 return GRUB_ERR_NONE
;
500 /* NOTE: This function assumes that given coordinates are within bounds of
503 common_blitter (struct grub_video_fbblit_info
*target
,
504 struct grub_video_fbblit_info
*source
,
505 enum grub_video_blit_operators oper
, int x
, int y
,
506 unsigned int width
, unsigned int height
,
507 int offset_x
, int offset_y
)
509 if (oper
== GRUB_VIDEO_BLIT_REPLACE
)
511 /* Try to figure out more optimized version for replace operator. */
512 if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
514 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
516 grub_video_fbblit_replace_directN (target
, source
,
521 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
523 grub_video_fbblit_replace_BGRX8888_RGBX8888 (target
, source
,
528 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
530 grub_video_fbblit_replace_BGR888_RGBX8888 (target
, source
,
535 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
537 grub_video_fbblit_replace_RGB888_RGBX8888 (target
, source
,
542 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
544 grub_video_fbblit_replace_index_RGBX8888 (target
, source
,
550 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
552 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
554 grub_video_fbblit_replace_BGRX8888_RGB888 (target
, source
,
559 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
561 grub_video_fbblit_replace_RGBX8888_RGB888 (target
, source
,
566 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
568 grub_video_fbblit_replace_BGR888_RGB888 (target
, source
,
573 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
575 grub_video_fbblit_replace_directN (target
, source
,
580 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
582 grub_video_fbblit_replace_index_RGB888 (target
, source
,
588 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
590 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
592 grub_video_fbblit_replace_directN (target
, source
,
598 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
600 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
602 grub_video_fbblit_replace_directN (target
, source
,
609 /* No optimized replace operator found, use default (slow) blitter. */
610 grub_video_fbblit_replace (target
, source
, x
, y
, width
, height
,
615 /* Try to figure out more optimized blend operator. */
616 if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
618 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
620 grub_video_fbblit_blend_BGRA8888_RGBA8888 (target
, source
,
625 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
627 grub_video_fbblit_blend_RGBA8888_RGBA8888 (target
, source
,
632 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
634 grub_video_fbblit_blend_BGR888_RGBA8888 (target
, source
,
639 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
641 grub_video_fbblit_blend_RGB888_RGBA8888 (target
, source
,
646 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
648 grub_video_fbblit_blend_index_RGBA8888 (target
, source
,
654 else if (source
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
656 /* Note: There is really no alpha information here, so blend is
657 changed to replace. */
659 if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
)
661 grub_video_fbblit_replace_BGRX8888_RGB888 (target
, source
,
666 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGBA_8888
)
668 grub_video_fbblit_replace_RGBX8888_RGB888 (target
, source
,
673 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_BGR_888
)
675 grub_video_fbblit_replace_BGR888_RGB888 (target
, source
,
680 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_RGB_888
)
682 grub_video_fbblit_replace_directN (target
, source
,
687 else if (target
->mode_info
->blit_format
== GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
)
689 grub_video_fbblit_replace_index_RGB888 (target
, source
,
696 /* No optimized blend operation found, use default (slow) blitter. */
697 grub_video_fbblit_blend (target
, source
, x
, y
, width
, height
,
703 grub_video_fb_blit_bitmap (struct grub_video_bitmap
*bitmap
,
704 enum grub_video_blit_operators oper
, int x
, int y
,
705 int offset_x
, int offset_y
,
706 unsigned int width
, unsigned int height
)
708 struct grub_video_fbblit_info source
;
709 struct grub_video_fbblit_info target
;
711 /* Make sure there is something to do. */
712 if ((width
== 0) || (height
== 0))
713 return GRUB_ERR_NONE
;
714 if ((x
>= (int)render_target
->viewport
.width
) || (x
+ (int)width
< 0))
715 return GRUB_ERR_NONE
;
716 if ((y
>= (int)render_target
->viewport
.height
) || (y
+ (int)height
< 0))
717 return GRUB_ERR_NONE
;
718 if ((x
+ (int)bitmap
->mode_info
.width
) < 0)
719 return GRUB_ERR_NONE
;
720 if ((y
+ (int)bitmap
->mode_info
.height
) < 0)
721 return GRUB_ERR_NONE
;
722 if ((offset_x
>= (int)bitmap
->mode_info
.width
)
723 || (offset_x
+ (int)width
< 0))
724 return GRUB_ERR_NONE
;
725 if ((offset_y
>= (int)bitmap
->mode_info
.height
)
726 || (offset_y
+ (int)height
< 0))
727 return GRUB_ERR_NONE
;
729 /* If we have negative coordinates, optimize drawing to minimum. */
758 /* Do not allow drawing out of viewport. */
759 if ((x
+ width
) > render_target
->viewport
.width
)
760 width
= render_target
->viewport
.width
- x
;
761 if ((y
+ height
) > render_target
->viewport
.height
)
762 height
= render_target
->viewport
.height
- y
;
764 if ((offset_x
+ width
) > bitmap
->mode_info
.width
)
765 width
= bitmap
->mode_info
.width
- offset_x
;
766 if ((offset_y
+ height
) > bitmap
->mode_info
.height
)
767 height
= bitmap
->mode_info
.height
- offset_y
;
769 /* Limit drawing to source render target dimensions. */
770 if (width
> bitmap
->mode_info
.width
)
771 width
= bitmap
->mode_info
.width
;
773 if (height
> bitmap
->mode_info
.height
)
774 height
= bitmap
->mode_info
.height
;
776 /* Add viewport offset. */
777 x
+= render_target
->viewport
.x
;
778 y
+= render_target
->viewport
.y
;
780 /* Use fbblit_info to encapsulate rendering. */
781 source
.mode_info
= &bitmap
->mode_info
;
782 source
.data
= bitmap
->data
;
783 target
.mode_info
= &render_target
->mode_info
;
784 target
.data
= render_target
->data
;
786 /* Do actual blitting. */
787 common_blitter (&target
, &source
, oper
, x
, y
, width
, height
,
790 return GRUB_ERR_NONE
;
794 grub_video_fb_blit_render_target (struct grub_video_fbrender_target
*source
,
795 enum grub_video_blit_operators oper
,
796 int x
, int y
, int offset_x
, int offset_y
,
797 unsigned int width
, unsigned int height
)
799 struct grub_video_fbblit_info source_info
;
800 struct grub_video_fbblit_info target_info
;
802 /* Make sure there is something to do. */
803 if ((width
== 0) || (height
== 0))
804 return GRUB_ERR_NONE
;
805 if ((x
>= (int)render_target
->viewport
.width
) || (x
+ (int)width
< 0))
806 return GRUB_ERR_NONE
;
807 if ((y
>= (int)render_target
->viewport
.height
) || (y
+ (int)height
< 0))
808 return GRUB_ERR_NONE
;
809 if ((x
+ (int)source
->mode_info
.width
) < 0)
810 return GRUB_ERR_NONE
;
811 if ((y
+ (int)source
->mode_info
.height
) < 0)
812 return GRUB_ERR_NONE
;
813 if ((offset_x
>= (int)source
->mode_info
.width
)
814 || (offset_x
+ (int)width
< 0))
815 return GRUB_ERR_NONE
;
816 if ((offset_y
>= (int)source
->mode_info
.height
)
817 || (offset_y
+ (int)height
< 0))
818 return GRUB_ERR_NONE
;
820 /* If we have negative coordinates, optimize drawing to minimum. */
849 /* Do not allow drawing out of viewport. */
850 if ((x
+ width
) > render_target
->viewport
.width
)
851 width
= render_target
->viewport
.width
- x
;
852 if ((y
+ height
) > render_target
->viewport
.height
)
853 height
= render_target
->viewport
.height
- y
;
855 if ((offset_x
+ width
) > source
->mode_info
.width
)
856 width
= source
->mode_info
.width
- offset_x
;
857 if ((offset_y
+ height
) > source
->mode_info
.height
)
858 height
= source
->mode_info
.height
- offset_y
;
860 /* Limit drawing to source render target dimensions. */
861 if (width
> source
->mode_info
.width
)
862 width
= source
->mode_info
.width
;
864 if (height
> source
->mode_info
.height
)
865 height
= source
->mode_info
.height
;
867 /* Add viewport offset. */
868 x
+= render_target
->viewport
.x
;
869 y
+= render_target
->viewport
.y
;
871 /* Use fbblit_info to encapsulate rendering. */
872 source_info
.mode_info
= &source
->mode_info
;
873 source_info
.data
= source
->data
;
874 target_info
.mode_info
= &render_target
->mode_info
;
875 target_info
.data
= render_target
->data
;
877 /* Do actual blitting. */
878 common_blitter (&target_info
, &source_info
, oper
, x
, y
, width
, height
,
881 return GRUB_ERR_NONE
;
885 grub_video_fb_scroll (grub_video_color_t color
, int dx
, int dy
)
894 /* 1. Check if we have something to do. */
895 if ((dx
== 0) && (dy
== 0))
896 return GRUB_ERR_NONE
;
898 width
= render_target
->viewport
.width
- grub_abs (dx
);
899 height
= render_target
->viewport
.height
- grub_abs (dy
);
903 src_x
= render_target
->viewport
.x
- dx
;
904 dst_x
= render_target
->viewport
.x
;
908 src_x
= render_target
->viewport
.x
;
909 dst_x
= render_target
->viewport
.x
+ dx
;
914 src_y
= render_target
->viewport
.y
- dy
;
915 dst_y
= render_target
->viewport
.y
;
919 src_y
= render_target
->viewport
.y
;
920 dst_y
= render_target
->viewport
.y
+ dy
;
923 /* 2. Check if there is need to copy data. */
924 if ((grub_abs (dx
) < render_target
->viewport
.width
)
925 && (grub_abs (dy
) < render_target
->viewport
.height
))
927 /* 3. Move data in render target. */
928 struct grub_video_fbblit_info target
;
933 target
.mode_info
= &render_target
->mode_info
;
934 target
.data
= render_target
->data
;
936 /* Check vertical direction of the move. */
938 /* 3a. Move data upwards. */
939 for (j
= 0; j
< height
; j
++)
941 dst
= grub_video_fb_get_video_ptr (&target
, dst_x
, dst_y
+ j
);
942 src
= grub_video_fb_get_video_ptr (&target
, src_x
, src_y
+ j
);
943 grub_memmove (dst
, src
,
944 width
* target
.mode_info
->bytes_per_pixel
);
947 /* 3b. Move data downwards. */
948 for (j
= (height
- 1); j
>= 0; j
--)
950 dst
= grub_video_fb_get_video_ptr (&target
, dst_x
, dst_y
+ j
);
951 src
= grub_video_fb_get_video_ptr (&target
, src_x
, src_y
+ j
);
952 grub_memmove (dst
, src
,
953 width
* target
.mode_info
->bytes_per_pixel
);
957 /* 4. Fill empty space with specified color. In this implementation
958 there might be colliding areas but at the moment there is no need
961 /* 4a. Fill top & bottom parts. */
963 grub_video_fb_fill_rect (color
, 0, 0, render_target
->viewport
.width
, dy
);
966 if (render_target
->viewport
.height
< grub_abs (dy
))
967 dy
= -render_target
->viewport
.height
;
969 grub_video_fb_fill_rect (color
, 0, render_target
->viewport
.height
+ dy
,
970 render_target
->viewport
.width
, -dy
);
973 /* 4b. Fill left & right parts. */
975 grub_video_fb_fill_rect (color
, 0, 0,
976 dx
, render_target
->viewport
.height
);
979 if (render_target
->viewport
.width
< grub_abs (dx
))
980 dx
= -render_target
->viewport
.width
;
982 grub_video_fb_fill_rect (color
, render_target
->viewport
.width
+ dx
, 0,
983 -dx
, render_target
->viewport
.height
);
986 return GRUB_ERR_NONE
;
991 grub_video_fb_create_render_target (struct grub_video_fbrender_target
**result
,
992 unsigned int width
, unsigned int height
,
993 unsigned int mode_type
__attribute__ ((unused
)))
995 struct grub_video_fbrender_target
*target
;
998 /* Validate arguments. */
1002 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
1003 "invalid argument given.");
1005 /* Allocate memory for render target. */
1006 target
= grub_malloc (sizeof (struct grub_video_fbrender_target
));
1010 /* TODO: Implement other types too.
1011 Currently only 32bit render targets are supported. */
1013 /* Mark render target as allocated. */
1014 target
->is_allocated
= 1;
1016 /* Maximize viewport. */
1017 target
->viewport
.x
= 0;
1018 target
->viewport
.y
= 0;
1019 target
->viewport
.width
= width
;
1020 target
->viewport
.height
= height
;
1022 /* Setup render target format. */
1023 target
->mode_info
.width
= width
;
1024 target
->mode_info
.height
= height
;
1025 target
->mode_info
.mode_type
= GRUB_VIDEO_MODE_TYPE_RGB
1026 | GRUB_VIDEO_MODE_TYPE_ALPHA
;
1027 target
->mode_info
.bpp
= 32;
1028 target
->mode_info
.bytes_per_pixel
= 4;
1029 target
->mode_info
.pitch
= target
->mode_info
.bytes_per_pixel
* width
;
1030 target
->mode_info
.number_of_colors
= palette_size
; /* Emulated palette. */
1031 target
->mode_info
.red_mask_size
= 8;
1032 target
->mode_info
.red_field_pos
= 0;
1033 target
->mode_info
.green_mask_size
= 8;
1034 target
->mode_info
.green_field_pos
= 8;
1035 target
->mode_info
.blue_mask_size
= 8;
1036 target
->mode_info
.blue_field_pos
= 16;
1037 target
->mode_info
.reserved_mask_size
= 8;
1038 target
->mode_info
.reserved_field_pos
= 24;
1040 target
->mode_info
.blit_format
= grub_video_get_blit_format (&target
->mode_info
);
1042 /* Calculate size needed for the data. */
1043 size
= (width
* target
->mode_info
.bytes_per_pixel
) * height
;
1045 target
->data
= grub_malloc (size
);
1052 /* Clear render target with black and maximum transparency. */
1053 grub_memset (target
->data
, 0, size
);
1055 /* TODO: Add render target to render target list. */
1057 /* Save result to caller. */
1060 return GRUB_ERR_NONE
;
1064 grub_video_fb_delete_render_target (struct grub_video_fbrender_target
*target
)
1066 /* If there is no target, then just return without error. */
1068 return GRUB_ERR_NONE
;
1070 /* TODO: Delist render target from render target list. */
1072 /* If this is software render target, free it's memory. */
1073 if (target
->is_allocated
)
1074 grub_free (target
->data
);
1076 /* Free render target. */
1079 return GRUB_ERR_NONE
;
1083 grub_video_fb_set_active_render_target (struct grub_video_fbrender_target
*target
)
1086 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
1087 "invalid render target given.");
1089 render_target
= target
;
1091 return GRUB_ERR_NONE
;
1095 grub_video_fb_get_active_render_target (struct grub_video_fbrender_target
**target
)
1097 *target
= render_target
;
1099 return GRUB_ERR_NONE
;