removed accidental commit
[grub2/phcoder.git] / video / fb / video_fb.c
blob98f80c3f4370871486ac6cb95ef3d56a4d841045
1 /*
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>
22 #include <grub/mm.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] =
36 // {R, G, B, A}
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
56 grub_err_t
57 grub_video_fb_init (void)
59 grub_free (palette);
60 render_target = 0;
61 palette = 0;
62 palette_size = 0;
63 return GRUB_ERR_NONE;
66 grub_err_t
67 grub_video_fb_fini (void)
69 grub_free (palette);
70 render_target = 0;
71 palette = 0;
72 palette_size = 0;
73 return GRUB_ERR_NONE;
76 grub_err_t
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));
83 return GRUB_ERR_NONE;
87 grub_uint8_t *
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)
95 case 32:
96 ptr = (grub_uint8_t *)source->data
97 + y * source->mode_info->pitch
98 + x * 4;
99 break;
101 case 24:
102 ptr = (grub_uint8_t *)source->data
103 + y * source->mode_info->pitch
104 + x * 3;
105 break;
107 case 16:
108 case 15:
109 ptr = (grub_uint8_t *)source->data
110 + y * source->mode_info->pitch
111 + x * 2;
112 break;
114 case 8:
115 ptr = (grub_uint8_t *)source->data
116 + y * source->mode_info->pitch
117 + x;
118 break;
121 return ptr;
124 grub_err_t
125 grub_video_fb_get_palette (unsigned int start, unsigned int count,
126 struct grub_video_palette_data *palette_data)
128 unsigned int i;
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;
137 grub_err_t
138 grub_video_fb_set_palette (unsigned int start, unsigned int count,
139 struct grub_video_palette_data *palette_data)
141 unsigned i;
142 if (start + count > palette_size)
144 palette_size = start + count;
145 palette = grub_realloc (palette, sizeof (palette[0]) * palette_size);
146 if (!palette)
148 grub_video_fb_fini ();
149 return grub_errno;
152 for (i = 0; (i < count) && ((i + start) < palette_size); i++)
153 palette[start + i] = palette_data[i];
154 return GRUB_ERR_NONE;
157 grub_err_t
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;
169 grub_err_t
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. */
182 grub_video_color_t
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)
191 return color_name;
192 else
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);
200 return color;
204 return 0;
207 /* Maps RGB to target optimized color format. */
208 grub_video_color_t
209 grub_video_fb_map_rgb (grub_uint8_t red, grub_uint8_t green,
210 grub_uint8_t blue)
212 if ((render_target->mode_info.mode_type
213 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
215 int minindex = 0;
216 int delta = 0;
217 int tmp;
218 int val;
219 unsigned i;
221 /* Find best matching color. */
222 for (i = 0; i < palette_size; i++)
224 val = palette[i].r - red;
225 tmp = val * val;
226 val = palette[i].g - green;
227 tmp += val * val;
228 val = palette[i].b - blue;
229 tmp += val * val;
231 if (i == 0)
232 delta = tmp;
234 if (tmp < delta)
236 delta = tmp;
237 minindex = i;
238 if (tmp == 0)
239 break;
243 return minindex;
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)
251 return 1;
252 else
253 return 0;
255 else
257 grub_uint32_t value;
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;
270 return value;
275 /* Maps RGBA to target optimized color format. */
276 grub_video_color_t
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)
292 return 1;
293 else
294 return 0;
296 else
298 grub_uint32_t value;
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;
310 return value;
314 /* Splits target optimized format to components. */
315 grub_err_t
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. */
331 void
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. */
344 if (color > 255)
346 *red = 0;
347 *green = 0;
348 *blue = 0;
349 *alpha = 0;
350 return;
353 *red = palette[color].r;
354 *green = palette[color].g;
355 *blue = palette[color].b;
356 *alpha = palette[color].a;
357 return;
359 else if ((mode_info->mode_type
360 & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
362 if (color & 1)
364 *red = mode_info->fg_red;
365 *green = mode_info->fg_green;
366 *blue = mode_info->fg_blue;
367 *alpha = mode_info->fg_alpha;
369 else
371 *red = mode_info->bg_red;
372 *green = mode_info->bg_green;
373 *blue = mode_info->bg_blue;
374 *alpha = mode_info->bg_alpha;
377 else
379 grub_uint32_t tmp;
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;
386 *red = tmp & 0xFF;
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;
393 *green = tmp & 0xFF;
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;
400 *blue = tmp & 0xFF;
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;
410 else
411 /* If there is no alpha component, assume it opaque. */
412 tmp = 255;
414 *alpha = tmp & 0xFF;
418 grub_err_t
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. */
431 if (x < 0)
433 width += x;
434 x = 0;
436 if (y < 0)
438 height += y;
439 y = 0;
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,
460 width, height);
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,
466 width, height);
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,
472 width, height);
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,
478 width, height);
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,
484 width, height);
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,
490 width, height);
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
501 handled data. */
502 static void
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,
517 x, y, width, height,
518 offset_x, offset_y);
519 return;
521 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
523 grub_video_fbblit_replace_BGRX8888_RGBX8888 (target, source,
524 x, y, width, height,
525 offset_x, offset_y);
526 return;
528 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
530 grub_video_fbblit_replace_BGR888_RGBX8888 (target, source,
531 x, y, width, height,
532 offset_x, offset_y);
533 return;
535 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
537 grub_video_fbblit_replace_RGB888_RGBX8888 (target, source,
538 x, y, width, height,
539 offset_x, offset_y);
540 return;
542 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
544 grub_video_fbblit_replace_index_RGBX8888 (target, source,
545 x, y, width, height,
546 offset_x, offset_y);
547 return;
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,
555 x, y, width, height,
556 offset_x, offset_y);
557 return;
559 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
561 grub_video_fbblit_replace_RGBX8888_RGB888 (target, source,
562 x, y, width, height,
563 offset_x, offset_y);
564 return;
566 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
568 grub_video_fbblit_replace_BGR888_RGB888 (target, source,
569 x, y, width, height,
570 offset_x, offset_y);
571 return;
573 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
575 grub_video_fbblit_replace_directN (target, source,
576 x, y, width, height,
577 offset_x, offset_y);
578 return;
580 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
582 grub_video_fbblit_replace_index_RGB888 (target, source,
583 x, y, width, height,
584 offset_x, offset_y);
585 return;
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,
593 x, y, width, height,
594 offset_x, offset_y);
595 return;
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,
603 x, y, width, height,
604 offset_x, offset_y);
605 return;
609 /* No optimized replace operator found, use default (slow) blitter. */
610 grub_video_fbblit_replace (target, source, x, y, width, height,
611 offset_x, offset_y);
613 else
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,
621 x, y, width, height,
622 offset_x, offset_y);
623 return;
625 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
627 grub_video_fbblit_blend_RGBA8888_RGBA8888 (target, source,
628 x, y, width, height,
629 offset_x, offset_y);
630 return;
632 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
634 grub_video_fbblit_blend_BGR888_RGBA8888 (target, source,
635 x, y, width, height,
636 offset_x, offset_y);
637 return;
639 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
641 grub_video_fbblit_blend_RGB888_RGBA8888 (target, source,
642 x, y, width, height,
643 offset_x, offset_y);
644 return;
646 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
648 grub_video_fbblit_blend_index_RGBA8888 (target, source,
649 x, y, width, height,
650 offset_x, offset_y);
651 return;
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,
662 x, y, width, height,
663 offset_x, offset_y);
664 return;
666 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
668 grub_video_fbblit_replace_RGBX8888_RGB888 (target, source,
669 x, y, width, height,
670 offset_x, offset_y);
671 return;
673 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
675 grub_video_fbblit_replace_BGR888_RGB888 (target, source,
676 x, y, width, height,
677 offset_x, offset_y);
678 return;
680 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
682 grub_video_fbblit_replace_directN (target, source,
683 x, y, width, height,
684 offset_x, offset_y);
685 return;
687 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
689 grub_video_fbblit_replace_index_RGB888 (target, source,
690 x, y, width, height,
691 offset_x, offset_y);
692 return;
696 /* No optimized blend operation found, use default (slow) blitter. */
697 grub_video_fbblit_blend (target, source, x, y, width, height,
698 offset_x, offset_y);
702 grub_err_t
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. */
730 if (offset_x < 0)
732 width += offset_x;
733 x -= offset_x;
734 offset_x = 0;
737 if (offset_y < 0)
739 height += offset_y;
740 y -= offset_y;
741 offset_y = 0;
744 if (x < 0)
746 width += x;
747 offset_x -= x;
748 x = 0;
751 if (y < 0)
753 height += y;
754 offset_y -= y;
755 y = 0;
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,
788 offset_x, offset_y);
790 return GRUB_ERR_NONE;
793 grub_err_t
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. */
821 if (offset_x < 0)
823 width += offset_x;
824 x -= offset_x;
825 offset_x = 0;
828 if (offset_y < 0)
830 height += offset_y;
831 y -= offset_y;
832 offset_y = 0;
835 if (x < 0)
837 width += x;
838 offset_x -= x;
839 x = 0;
842 if (y < 0)
844 height += y;
845 offset_y -= y;
846 y = 0;
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,
879 offset_x, offset_y);
881 return GRUB_ERR_NONE;
884 grub_err_t
885 grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
887 int width;
888 int height;
889 int src_x;
890 int src_y;
891 int dst_x;
892 int dst_y;
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);
901 if (dx < 0)
903 src_x = render_target->viewport.x - dx;
904 dst_x = render_target->viewport.x;
906 else
908 src_x = render_target->viewport.x;
909 dst_x = render_target->viewport.x + dx;
912 if (dy < 0)
914 src_y = render_target->viewport.y - dy;
915 dst_y = render_target->viewport.y;
917 else
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;
929 grub_uint8_t *src;
930 grub_uint8_t *dst;
931 int j;
933 target.mode_info = &render_target->mode_info;
934 target.data = render_target->data;
936 /* Check vertical direction of the move. */
937 if (dy <= 0)
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);
946 else
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
959 to optimize this. */
961 /* 4a. Fill top & bottom parts. */
962 if (dy > 0)
963 grub_video_fb_fill_rect (color, 0, 0, render_target->viewport.width, dy);
964 else if (dy < 0)
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. */
974 if (dx > 0)
975 grub_video_fb_fill_rect (color, 0, 0,
976 dx, render_target->viewport.height);
977 else if (dx < 0)
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;
990 grub_err_t
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;
996 unsigned int size;
998 /* Validate arguments. */
999 if ((! result)
1000 || (width == 0)
1001 || (height == 0))
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));
1007 if (! target)
1008 return grub_errno;
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);
1046 if (! target->data)
1048 grub_free (target);
1049 return grub_errno;
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. */
1058 *result = target;
1060 return GRUB_ERR_NONE;
1063 grub_err_t
1064 grub_video_fb_delete_render_target (struct grub_video_fbrender_target *target)
1066 /* If there is no target, then just return without error. */
1067 if (! target)
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. */
1077 grub_free (target);
1079 return GRUB_ERR_NONE;
1082 grub_err_t
1083 grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target)
1085 if (! target->data)
1086 return grub_error (GRUB_ERR_BAD_ARGUMENT,
1087 "invalid render target given.");
1089 render_target = target;
1091 return GRUB_ERR_NONE;
1094 grub_err_t
1095 grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **target)
1097 *target = render_target;
1099 return GRUB_ERR_NONE;