Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / common / boot / grub2 / video / i386 / pc / vbe.c
blob41660ac06f5bf6bb1bb13a8fd38ff03a46a84a99
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2005,2006,2007,2008 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/err.h>
20 #include <grub/machine/memory.h>
21 #include <grub/machine/vga.h>
22 #include <grub/machine/vbe.h>
23 #include <grub/machine/vbeblit.h>
24 #include <grub/machine/vbefill.h>
25 #include <grub/machine/vbeutil.h>
26 #include <grub/types.h>
27 #include <grub/dl.h>
28 #include <grub/misc.h>
29 #include <grub/font.h>
30 #include <grub/mm.h>
31 #include <grub/video.h>
32 #include <grub/bitmap.h>
34 /* Specify "standard" VGA palette, some video cards may
35 need this and this will also be used when using RGB modes. */
36 static struct grub_vbe_palette_data vga_colors[16] =
38 // {B, G, R, A}
39 {0x00, 0x00, 0x00, 0x00}, // 0 = black
40 {0xA8, 0x00, 0x00, 0x00}, // 1 = blue
41 {0x00, 0xA8, 0x00, 0x00}, // 2 = green
42 {0xA8, 0xA8, 0x00, 0x00}, // 3 = cyan
43 {0x00, 0x00, 0xA8, 0x00}, // 4 = red
44 {0xA8, 0x00, 0xA8, 0x00}, // 5 = magenta
45 {0x00, 0x54, 0xA8, 0x00}, // 6 = brown
46 {0xA8, 0xA8, 0xA8, 0x00}, // 7 = ligth gray
48 {0x54, 0x54, 0x54, 0x00}, // 8 = dark gray
49 {0xFE, 0x54, 0x54, 0x00}, // 9 = bright blue
50 {0x54, 0xFE, 0x54, 0x00}, // 10 = bright green
51 {0xFE, 0xFE, 0x54, 0x00}, // 11 = bright cyan
52 {0x54, 0x54, 0xFE, 0x00}, // 12 = bright red
53 {0xFE, 0x54, 0xFE, 0x00}, // 13 = bright magenta
54 {0x54, 0xFE, 0xFE, 0x00}, // 14 = yellow
55 {0xFE, 0xFE, 0xFE, 0x00} // 15 = white
58 static int vbe_detected = -1;
60 static struct grub_vbe_info_block controller_info;
61 static struct grub_vbe_mode_info_block active_mode_info;
63 static struct
65 struct grub_video_render_target render_target;
67 unsigned int bytes_per_scan_line;
68 unsigned int bytes_per_pixel;
69 grub_uint32_t active_mode;
70 grub_uint8_t *ptr;
71 int index_color_mode;
72 struct grub_video_palette_data palette[256];
73 } framebuffer;
75 static struct grub_video_render_target *render_target;
76 static grub_uint32_t initial_mode;
77 static grub_uint32_t mode_in_use = 0x55aa;
78 static grub_uint16_t *mode_list;
80 static void *
81 real2pm (grub_vbe_farptr_t ptr)
83 return (void *) ((((unsigned long) ptr & 0xFFFF0000) >> 12UL)
84 + ((unsigned long) ptr & 0x0000FFFF));
87 grub_err_t
88 grub_vbe_probe (struct grub_vbe_info_block *info_block)
90 struct grub_vbe_info_block *vbe_ib;
91 grub_vbe_status_t status;
93 /* Clear caller's controller info block. */
94 if (info_block)
95 grub_memset (info_block, 0, sizeof (*info_block));
97 /* Do not probe more than one time, if not necessary. */
98 if (vbe_detected == -1 || info_block)
100 /* Clear old copy of controller info block. */
101 grub_memset (&controller_info, 0, sizeof (controller_info));
103 /* Mark VESA BIOS extension as undetected. */
104 vbe_detected = 0;
106 /* Use low memory scratch area as temporary storage
107 for VESA BIOS call. */
108 vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
110 /* Prepare info block. */
111 grub_memset (vbe_ib, 0, sizeof (*vbe_ib));
113 vbe_ib->signature[0] = 'V';
114 vbe_ib->signature[1] = 'B';
115 vbe_ib->signature[2] = 'E';
116 vbe_ib->signature[3] = '2';
118 /* Try to get controller info block. */
119 status = grub_vbe_bios_get_controller_info (vbe_ib);
120 if (status == 0x004F)
122 /* Copy it for later usage. */
123 grub_memcpy (&controller_info, vbe_ib, sizeof (controller_info));
125 /* Mark VESA BIOS extension as detected. */
126 vbe_detected = 1;
130 if (! vbe_detected)
131 return grub_error (GRUB_ERR_BAD_DEVICE, "VESA BIOS Extension not found");
133 /* Make copy of controller info block to caller. */
134 if (info_block)
135 grub_memcpy (info_block, &controller_info, sizeof (*info_block));
137 return GRUB_ERR_NONE;
140 grub_err_t
141 grub_vbe_set_video_mode (grub_uint32_t mode,
142 struct grub_vbe_mode_info_block *mode_info)
144 grub_vbe_status_t status;
145 grub_uint32_t old_mode;
147 /* Make sure that VBE is supported. */
148 grub_vbe_probe (0);
149 if (grub_errno != GRUB_ERR_NONE)
150 return grub_errno;
152 /* Try to get mode info. */
153 grub_vbe_get_video_mode_info (mode, &active_mode_info);
154 if (grub_errno != GRUB_ERR_NONE)
155 return grub_errno;
157 /* For all VESA BIOS modes, force linear frame buffer. */
158 if (mode >= 0x100)
160 /* We only want linear frame buffer modes. */
161 mode |= 1 << 14;
163 /* Determine frame buffer pixel format. */
164 switch (active_mode_info.memory_model)
166 case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL:
167 framebuffer.index_color_mode = 1;
168 break;
170 case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR:
171 framebuffer.index_color_mode = 0;
172 break;
174 default:
175 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
176 "unsupported pixel format 0x%x",
177 active_mode_info.memory_model);
181 /* Get current mode. */
182 grub_vbe_get_video_mode (&old_mode);
183 if (grub_errno != GRUB_ERR_NONE)
184 return grub_errno;
186 /* Try to set video mode. */
187 status = grub_vbe_bios_set_mode (mode, 0);
188 if (status != GRUB_VBE_STATUS_OK)
189 return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", mode);
191 /* Save information for later usage. */
192 framebuffer.active_mode = mode;
194 if (mode < 0x100)
196 /* If this is not a VESA mode, guess address. */
197 framebuffer.ptr = (grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR;
198 framebuffer.index_color_mode = 1;
200 else
202 framebuffer.ptr = (grub_uint8_t *) active_mode_info.phys_base_addr;
204 if (controller_info.version >= 0x300)
205 framebuffer.bytes_per_scan_line = active_mode_info.lin_bytes_per_scan_line;
206 else
207 framebuffer.bytes_per_scan_line = active_mode_info.bytes_per_scan_line;
210 /* Calculate bytes_per_pixel value. */
211 switch(active_mode_info.bits_per_pixel)
213 case 32: framebuffer.bytes_per_pixel = 4; break;
214 case 24: framebuffer.bytes_per_pixel = 3; break;
215 case 16: framebuffer.bytes_per_pixel = 2; break;
216 case 15: framebuffer.bytes_per_pixel = 2; break;
217 case 8: framebuffer.bytes_per_pixel = 1; break;
218 default:
219 grub_vbe_bios_set_mode (old_mode, 0);
220 return grub_error (GRUB_ERR_BAD_DEVICE,
221 "cannot set VBE mode %x",
222 mode);
223 break;
226 /* If video mode is in indexed color, setup default VGA palette. */
227 if (framebuffer.index_color_mode)
229 struct grub_vbe_palette_data *palette
230 = (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
232 /* Make sure that the BIOS can reach the palette. */
233 grub_memcpy (palette, vga_colors, sizeof (vga_colors));
234 status = grub_vbe_bios_set_palette_data (sizeof (vga_colors)
235 / sizeof (struct grub_vbe_palette_data),
237 palette);
239 /* Just ignore the status. */
242 /* Copy mode info for caller. */
243 if (mode_info)
244 grub_memcpy (mode_info, &active_mode_info, sizeof (*mode_info));
246 return GRUB_ERR_NONE;
249 grub_err_t
250 grub_vbe_get_video_mode (grub_uint32_t *mode)
252 grub_vbe_status_t status;
254 /* Make sure that VBE is supported. */
255 grub_vbe_probe (0);
256 if (grub_errno != GRUB_ERR_NONE)
257 return grub_errno;
259 /* Try to query current mode from VESA BIOS. */
260 status = grub_vbe_bios_get_mode (mode);
261 if (status != GRUB_VBE_STATUS_OK)
262 return grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current VBE mode");
264 return GRUB_ERR_NONE;
267 grub_err_t
268 grub_vbe_get_video_mode_info (grub_uint32_t mode,
269 struct grub_vbe_mode_info_block *mode_info)
271 struct grub_vbe_mode_info_block *mi_tmp
272 = (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
273 grub_vbe_status_t status;
275 /* Make sure that VBE is supported. */
276 grub_vbe_probe (0);
277 if (grub_errno != GRUB_ERR_NONE)
278 return grub_errno;
280 /* If mode is not VESA mode, skip mode info query. */
281 if (mode >= 0x100)
283 /* Try to get mode info from VESA BIOS. */
284 status = grub_vbe_bios_get_mode_info (mode, mi_tmp);
285 if (status != GRUB_VBE_STATUS_OK)
286 return grub_error (GRUB_ERR_BAD_DEVICE,
287 "cannot get information on the mode %x", mode);
289 /* Make copy of mode info block. */
290 grub_memcpy (mode_info, mi_tmp, sizeof (*mode_info));
292 else
293 /* Just clear mode info block if it isn't a VESA mode. */
294 grub_memset (mode_info, 0, sizeof (*mode_info));
296 return GRUB_ERR_NONE;
299 grub_uint8_t *
300 grub_video_vbe_get_video_ptr (struct grub_video_i386_vbeblit_info *source,
301 grub_uint32_t x, grub_uint32_t y)
303 grub_uint8_t *ptr = 0;
305 switch (source->mode_info->bpp)
307 case 32:
308 ptr = (grub_uint8_t *)source->data
309 + y * source->mode_info->pitch
310 + x * 4;
311 break;
313 case 24:
314 ptr = (grub_uint8_t *)source->data
315 + y * source->mode_info->pitch
316 + x * 3;
317 break;
319 case 16:
320 case 15:
321 ptr = (grub_uint8_t *)source->data
322 + y * source->mode_info->pitch
323 + x * 2;
324 break;
326 case 8:
327 ptr = (grub_uint8_t *)source->data
328 + y * source->mode_info->pitch
329 + x;
330 break;
333 return ptr;
336 static grub_err_t
337 grub_video_vbe_init (void)
339 grub_uint16_t *rm_mode_list;
340 grub_uint16_t *p;
341 grub_size_t mode_list_size;
342 struct grub_vbe_info_block info_block;
344 /* Check if there is adapter present.
346 Firmware note: There has been a report that some cards store video mode
347 list in temporary memory. So we must first use vbe probe to get
348 refreshed information to receive valid pointers and data, and then
349 copy this information to somewhere safe. */
350 grub_vbe_probe (&info_block);
351 if (grub_errno != GRUB_ERR_NONE)
352 return grub_errno;
354 /* Copy modelist to local memory. */
355 p = rm_mode_list = real2pm (info_block.video_mode_ptr);
356 while(*p++ != 0xFFFF)
359 mode_list_size = (grub_addr_t) p - (grub_addr_t) rm_mode_list;
360 mode_list = grub_malloc (mode_list_size);
361 if (! mode_list)
362 return grub_errno;
363 grub_memcpy (mode_list, rm_mode_list, mode_list_size);
365 /* Adapter could be found, figure out initial video mode. */
366 grub_vbe_get_video_mode (&initial_mode);
367 if (grub_errno != GRUB_ERR_NONE)
369 /* Free allocated resources. */
370 grub_free (mode_list);
371 mode_list = 0;
373 return grub_errno;
376 /* Reset frame buffer and render target variables. */
377 grub_memset (&framebuffer, 0, sizeof(framebuffer));
378 render_target = &framebuffer.render_target;
380 return GRUB_ERR_NONE;
383 static grub_err_t
384 grub_video_vbe_fini (void)
386 grub_vbe_status_t status;
388 /* Restore old video mode. */
389 status = grub_vbe_bios_set_mode (initial_mode, 0);
390 if (status != GRUB_VBE_STATUS_OK)
391 /* TODO: Decide, is this something we want to do. */
392 return grub_errno;
394 /* TODO: Free any resources allocated by driver. */
395 grub_free (mode_list);
396 mode_list = 0;
398 /* TODO: destroy render targets. */
400 /* Return success to caller. */
401 return GRUB_ERR_NONE;
404 static grub_err_t
405 grub_video_vbe_setup (unsigned int width, unsigned int height,
406 unsigned int mode_type)
408 grub_uint16_t *p;
409 struct grub_vbe_mode_info_block mode_info;
410 struct grub_vbe_mode_info_block best_mode_info;
411 grub_uint32_t best_mode = 0;
412 int depth;
413 unsigned int i;
415 /* Decode depth from mode_type. If it is zero, then autodetect. */
416 depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
417 >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
419 /* Walk thru mode list and try to find matching mode. */
420 for (p = mode_list; *p != 0xFFFF; p++)
422 grub_uint32_t mode = *p;
424 grub_vbe_get_video_mode_info (mode, &mode_info);
425 if (grub_errno != GRUB_ERR_NONE)
427 /* Could not retrieve mode info, retreat. */
428 grub_errno = GRUB_ERR_NONE;
429 break;
432 if ((mode_info.mode_attributes & 0x001) == 0)
433 /* If not available, skip it. */
434 continue;
436 if ((mode_info.mode_attributes & 0x002) == 0)
437 /* Not enough information. */
438 continue;
440 if ((mode_info.mode_attributes & 0x008) == 0)
441 /* Monochrome is unusable. */
442 continue;
444 if ((mode_info.mode_attributes & 0x080) == 0)
445 /* We support only linear frame buffer modes. */
446 continue;
448 if ((mode_info.mode_attributes & 0x010) == 0)
449 /* We allow only graphical modes. */
450 continue;
452 if ((mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
453 && (mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR))
454 /* Not compatible memory model. */
455 continue;
457 if ((mode_info.x_resolution != width)
458 || (mode_info.y_resolution != height))
459 /* Non matching resolution. */
460 continue;
462 /* Check if user requested RGB or index color mode. */
463 if ((mode_type & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0)
465 if (((mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
466 && (mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL))
467 /* Requested only index color modes. */
468 continue;
470 if (((mode_type & GRUB_VIDEO_MODE_TYPE_RGB) != 0)
471 && (mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR))
472 /* Requested only RGB modes. */
473 continue;
476 /* If there is a request for specific depth, ignore others. */
477 if ((depth != 0) && (mode_info.bits_per_pixel != depth))
478 continue;
480 /* Select mode with most number of bits per pixel. */
481 if (best_mode != 0)
482 if (mode_info.bits_per_pixel < best_mode_info.bits_per_pixel)
483 continue;
485 /* Save so far best mode information for later use. */
486 best_mode = mode;
487 grub_memcpy (&best_mode_info, &mode_info, sizeof (mode_info));
490 /* Try to initialize best mode found. */
491 if (best_mode != 0)
493 /* If this fails, then we have mode selection heuristics problem,
494 or adapter failure. */
495 grub_vbe_set_video_mode (best_mode, &active_mode_info);
496 if (grub_errno != GRUB_ERR_NONE)
497 return grub_errno;
499 /* Now we are happily in requested video mode. Cache some info
500 in order to fasten later operations. */
501 mode_in_use = best_mode;
503 /* Reset render target to framebuffer one. */
504 render_target = &framebuffer.render_target;
506 /* Fill mode info details in framebuffer's render target. */
507 render_target->mode_info.width = active_mode_info.x_resolution;
508 render_target->mode_info.height = active_mode_info.y_resolution;
510 if (framebuffer.index_color_mode)
511 render_target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
512 else
513 render_target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
515 render_target->mode_info.bpp = active_mode_info.bits_per_pixel;
516 render_target->mode_info.bytes_per_pixel = framebuffer.bytes_per_pixel;
517 render_target->mode_info.pitch = framebuffer.bytes_per_scan_line;
518 render_target->mode_info.number_of_colors = 256; /* TODO: fix me. */
519 render_target->mode_info.red_mask_size = active_mode_info.red_mask_size;
520 render_target->mode_info.red_field_pos = active_mode_info.red_field_position;
521 render_target->mode_info.green_mask_size = active_mode_info.green_mask_size;
522 render_target->mode_info.green_field_pos = active_mode_info.green_field_position;
523 render_target->mode_info.blue_mask_size = active_mode_info.blue_mask_size;
524 render_target->mode_info.blue_field_pos = active_mode_info.blue_field_position;
525 render_target->mode_info.reserved_mask_size = active_mode_info.rsvd_mask_size;
526 render_target->mode_info.reserved_field_pos = active_mode_info.rsvd_field_position;
528 render_target->mode_info.blit_format = grub_video_get_blit_format (&render_target->mode_info);
530 /* Reset viewport to match new mode. */
531 render_target->viewport.x = 0;
532 render_target->viewport.y = 0;
533 render_target->viewport.width = active_mode_info.x_resolution;
534 render_target->viewport.height = active_mode_info.y_resolution;
536 /* Set framebuffer pointer and mark it as non allocated. */
537 render_target->is_allocated = 0;
538 render_target->data = framebuffer.ptr;
540 /* Copy default palette to initialize emulated palette. */
541 for (i = 0;
542 i < (sizeof (vga_colors)
543 / sizeof (struct grub_vbe_palette_data));
544 i++)
546 framebuffer.palette[i].r = vga_colors[i].red;
547 framebuffer.palette[i].g = vga_colors[i].green;
548 framebuffer.palette[i].b = vga_colors[i].blue;
549 framebuffer.palette[i].a = 0xFF;
552 return GRUB_ERR_NONE;
555 /* Couldn't found matching mode. */
556 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found.");
559 static grub_err_t
560 grub_video_vbe_get_info (struct grub_video_mode_info *mode_info)
562 /* Copy mode info from active render target. */
563 grub_memcpy (mode_info, &render_target->mode_info,
564 sizeof (struct grub_video_mode_info));
566 return GRUB_ERR_NONE;
569 static grub_err_t
570 grub_video_vbe_set_palette (unsigned int start, unsigned int count,
571 struct grub_video_palette_data *palette_data)
573 unsigned int i;
575 if (framebuffer.index_color_mode)
577 /* TODO: Implement setting indexed color mode palette to hardware. */
578 //status = grub_vbe_bios_set_palette_data (sizeof (vga_colors)
579 // / sizeof (struct grub_vbe_palette_data),
580 // 0,
581 // palette);
585 /* Then set color to emulated palette. */
586 for (i = 0; (i < count) && ((i + start) < 256); i++)
587 framebuffer.palette[start + i] = palette_data[i];
589 return GRUB_ERR_NONE;
592 static grub_err_t
593 grub_video_vbe_get_palette (unsigned int start, unsigned int count,
594 struct grub_video_palette_data *palette_data)
596 unsigned int i;
598 /* Assume that we know everything from index color palette. */
599 for (i = 0; (i < count) && ((i + start) < 256); i++)
600 palette_data[i] = framebuffer.palette[start + i];
602 return GRUB_ERR_NONE;
605 static grub_err_t
606 grub_video_vbe_set_viewport (unsigned int x, unsigned int y,
607 unsigned int width, unsigned int height)
609 /* Make sure viewport is withing screen dimensions. If viewport was set
610 to be out of the region, mark its size as zero. */
611 if (x > active_mode_info.x_resolution)
613 x = 0;
614 width = 0;
617 if (y > active_mode_info.y_resolution)
619 y = 0;
620 height = 0;
623 if (x + width > active_mode_info.x_resolution)
624 width = active_mode_info.x_resolution - x;
626 if (y + height > active_mode_info.y_resolution)
627 height = active_mode_info.y_resolution - y;
629 render_target->viewport.x = x;
630 render_target->viewport.y = y;
631 render_target->viewport.width = width;
632 render_target->viewport.height = height;
634 return GRUB_ERR_NONE;
637 static grub_err_t
638 grub_video_vbe_get_viewport (unsigned int *x, unsigned int *y,
639 unsigned int *width, unsigned int *height)
641 if (x) *x = render_target->viewport.x;
642 if (y) *y = render_target->viewport.y;
643 if (width) *width = render_target->viewport.width;
644 if (height) *height = render_target->viewport.height;
646 return GRUB_ERR_NONE;
649 /* Maps color name to target optimized color format. */
650 static grub_video_color_t
651 grub_video_vbe_map_color (grub_uint32_t color_name)
653 /* TODO: implement color theme mapping code. */
655 if (color_name < 256)
657 if ((render_target->mode_info.mode_type
658 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
659 return color_name;
660 else
662 grub_video_color_t color;
664 color = grub_video_vbe_map_rgb (framebuffer.palette[color_name].r,
665 framebuffer.palette[color_name].g,
666 framebuffer.palette[color_name].b);
668 return color;
672 return 0;
675 /* Maps RGB to target optimized color format. */
676 grub_video_color_t
677 grub_video_vbe_map_rgb (grub_uint8_t red, grub_uint8_t green,
678 grub_uint8_t blue)
680 if ((render_target->mode_info.mode_type
681 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
683 int minindex = 0;
684 int delta = 0;
685 int tmp;
686 int val;
687 int i;
689 /* Find best matching color. */
690 for (i = 0; i < 256; i++)
692 val = framebuffer.palette[i].r - red;
693 tmp = val * val;
694 val = framebuffer.palette[i].g - green;
695 tmp += val * val;
696 val = framebuffer.palette[i].b - blue;
697 tmp += val * val;
699 if (i == 0)
700 delta = tmp;
702 if (tmp < delta)
704 delta = tmp;
705 minindex = i;
706 if (tmp == 0)
707 break;
711 return minindex;
713 else
715 grub_uint32_t value;
716 grub_uint8_t alpha = 255; /* Opaque color. */
718 red >>= 8 - render_target->mode_info.red_mask_size;
719 green >>= 8 - render_target->mode_info.green_mask_size;
720 blue >>= 8 - render_target->mode_info.blue_mask_size;
721 alpha >>= 8 - render_target->mode_info.reserved_mask_size;
723 value = red << render_target->mode_info.red_field_pos;
724 value |= green << render_target->mode_info.green_field_pos;
725 value |= blue << render_target->mode_info.blue_field_pos;
726 value |= alpha << render_target->mode_info.reserved_field_pos;
728 return value;
733 /* Maps RGBA to target optimized color format. */
734 grub_video_color_t
735 grub_video_vbe_map_rgba (grub_uint8_t red, grub_uint8_t green,
736 grub_uint8_t blue, grub_uint8_t alpha)
738 if ((render_target->mode_info.mode_type
739 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
740 /* No alpha available in index color modes, just use
741 same value as in only RGB modes. */
742 return grub_video_vbe_map_rgb (red, green, blue);
743 else
745 grub_uint32_t value;
747 red >>= 8 - render_target->mode_info.red_mask_size;
748 green >>= 8 - render_target->mode_info.green_mask_size;
749 blue >>= 8 - render_target->mode_info.blue_mask_size;
750 alpha >>= 8 - render_target->mode_info.reserved_mask_size;
752 value = red << render_target->mode_info.red_field_pos;
753 value |= green << render_target->mode_info.green_field_pos;
754 value |= blue << render_target->mode_info.blue_field_pos;
755 value |= alpha << render_target->mode_info.reserved_field_pos;
757 return value;
761 /* Splits target optimized format to components. */
762 grub_err_t grub_video_vbe_unmap_color (grub_video_color_t color,
763 grub_uint8_t *red, grub_uint8_t *green,
764 grub_uint8_t *blue, grub_uint8_t *alpha)
766 struct grub_video_i386_vbeblit_info target_info;
768 target_info.mode_info = &render_target->mode_info;
769 target_info.data = render_target->data;
771 grub_video_vbe_unmap_color_int (&target_info, color, red, green, blue, alpha);
773 return GRUB_ERR_NONE;
776 /* Splits color in source format to components. */
777 void
778 grub_video_vbe_unmap_color_int (struct grub_video_i386_vbeblit_info * source,
779 grub_video_color_t color,
780 grub_uint8_t *red, grub_uint8_t *green,
781 grub_uint8_t *blue, grub_uint8_t *alpha)
783 struct grub_video_mode_info *mode_info;
784 mode_info = source->mode_info;
786 if ((mode_info->mode_type
787 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
789 /* If we have an out-of-bounds color, return transparent black. */
790 if (color > 255)
792 *red = 0;
793 *green = 0;
794 *blue = 0;
795 *alpha = 0;
796 return;
799 *red = framebuffer.palette[color].r;
800 *green = framebuffer.palette[color].g;
801 *blue = framebuffer.palette[color].b;
802 *alpha = framebuffer.palette[color].a;
803 return;
805 else
807 grub_uint32_t tmp;
809 /* Get red component. */
810 tmp = color >> mode_info->red_field_pos;
811 tmp &= (1 << mode_info->red_mask_size) - 1;
812 tmp <<= 8 - mode_info->red_mask_size;
813 tmp |= (1 << (8 - mode_info->red_mask_size)) - 1;
814 *red = tmp & 0xFF;
816 /* Get green component. */
817 tmp = color >> mode_info->green_field_pos;
818 tmp &= (1 << mode_info->green_mask_size) - 1;
819 tmp <<= 8 - mode_info->green_mask_size;
820 tmp |= (1 << (8 - mode_info->green_mask_size)) - 1;
821 *green = tmp & 0xFF;
823 /* Get blue component. */
824 tmp = color >> mode_info->blue_field_pos;
825 tmp &= (1 << mode_info->blue_mask_size) - 1;
826 tmp <<= 8 - mode_info->blue_mask_size;
827 tmp |= (1 << (8 - mode_info->blue_mask_size)) - 1;
828 *blue = tmp & 0xFF;
830 /* Get alpha component. */
831 if (source->mode_info->reserved_mask_size > 0)
833 tmp = color >> mode_info->reserved_field_pos;
834 tmp &= (1 << mode_info->reserved_mask_size) - 1;
835 tmp <<= 8 - mode_info->reserved_mask_size;
836 tmp |= (1 << (8 - mode_info->reserved_mask_size)) - 1;
838 else
839 /* If there is no alpha component, assume it opaque. */
840 tmp = 255;
842 *alpha = tmp & 0xFF;
846 static grub_err_t
847 grub_video_vbe_fill_rect (grub_video_color_t color, int x, int y,
848 unsigned int width, unsigned int height)
850 struct grub_video_i386_vbeblit_info target;
852 /* Make sure there is something to do. */
853 if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0))
854 return GRUB_ERR_NONE;
855 if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0))
856 return GRUB_ERR_NONE;
858 /* Do not allow drawing out of viewport. */
859 if (x < 0)
861 width += x;
862 x = 0;
864 if (y < 0)
866 height += y;
867 y = 0;
870 if ((x + width) > render_target->viewport.width)
871 width = render_target->viewport.width - x;
872 if ((y + height) > render_target->viewport.height)
873 height = render_target->viewport.height - y;
875 /* Add viewport offset. */
876 x += render_target->viewport.x;
877 y += render_target->viewport.y;
879 /* Use vbeblit_info to encapsulate rendering. */
880 target.mode_info = &render_target->mode_info;
881 target.data = render_target->data;
883 /* Try to figure out more optimized version. Note that color is already
884 mapped to target format so we can make assumptions based on that. */
885 if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
887 grub_video_i386_vbefill_direct32 (&target, color, x, y,
888 width, height);
889 return GRUB_ERR_NONE;
891 else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
893 grub_video_i386_vbefill_direct32 (&target, color, x, y,
894 width, height);
895 return GRUB_ERR_NONE;
897 else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
899 grub_video_i386_vbefill_direct24 (&target, color, x, y,
900 width, height);
901 return GRUB_ERR_NONE;
903 else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_565)
905 grub_video_i386_vbefill_direct16 (&target, color, x, y,
906 width, height);
907 return GRUB_ERR_NONE;
909 else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_565)
911 grub_video_i386_vbefill_direct16 (&target, color, x, y,
912 width, height);
913 return GRUB_ERR_NONE;
915 else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
917 grub_video_i386_vbefill_direct8 (&target, color, x, y,
918 width, height);
919 return GRUB_ERR_NONE;
922 /* No optimized version found, use default (slow) filler. */
923 grub_video_i386_vbefill (&target, color, x, y, width, height);
925 return GRUB_ERR_NONE;
928 // TODO: Remove this method and replace with bitmap based glyphs
929 static grub_err_t
930 grub_video_vbe_blit_glyph (struct grub_font_glyph * glyph,
931 grub_video_color_t color, int x, int y)
933 struct grub_video_i386_vbeblit_info target;
934 unsigned int width;
935 unsigned int charwidth;
936 unsigned int height;
937 unsigned int i;
938 unsigned int j;
939 unsigned int x_offset = 0;
940 unsigned int y_offset = 0;
942 /* Make sure there is something to do. */
943 if (x >= (int)render_target->viewport.width)
944 return GRUB_ERR_NONE;
946 if (y >= (int)render_target->viewport.height)
947 return GRUB_ERR_NONE;
949 /* Calculate glyph dimensions. */
950 width = ((glyph->width + 7) / 8) * 8;
951 charwidth = width;
952 height = glyph->height;
954 if (x + (int)width < 0)
955 return GRUB_ERR_NONE;
957 if (y + (int)height < 0)
958 return GRUB_ERR_NONE;
960 /* Do not allow drawing out of viewport. */
961 if (x < 0)
963 width += x;
964 x_offset = (unsigned int)-x;
965 x = 0;
967 if (y < 0)
969 height += y;
970 y_offset = (unsigned int)-y;
971 y = 0;
974 if ((x + width) > render_target->viewport.width)
975 width = render_target->viewport.width - x;
976 if ((y + height) > render_target->viewport.height)
977 height = render_target->viewport.height - y;
979 /* Add viewport offset. */
980 x += render_target->viewport.x;
981 y += render_target->viewport.y;
983 /* Use vbeblit_info to encapsulate rendering. */
984 target.mode_info = &render_target->mode_info;
985 target.data = render_target->data;
987 /* Draw glyph. */
988 for (j = 0; j < height; j++)
989 for (i = 0; i < width; i++)
990 if ((glyph->bitmap[((i + x_offset) / 8)
991 + (j + y_offset) * (charwidth / 8)]
992 & (1 << ((charwidth - (i + x_offset) - 1) % 8))))
993 set_pixel (&target, x+i, y+j, color);
995 return GRUB_ERR_NONE;
998 /* NOTE: This function assumes that given coordinates are within bounds of
999 handled data. */
1000 static void
1001 common_blitter (struct grub_video_i386_vbeblit_info *target,
1002 struct grub_video_i386_vbeblit_info *source,
1003 enum grub_video_blit_operators oper, int x, int y,
1004 unsigned int width, unsigned int height,
1005 int offset_x, int offset_y)
1007 if (oper == GRUB_VIDEO_BLIT_REPLACE)
1009 /* Try to figure out more optimized version for replace operator. */
1010 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
1012 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
1014 grub_video_i386_vbeblit_replace_directN (target, source,
1015 x, y, width, height,
1016 offset_x, offset_y);
1017 return;
1019 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
1021 grub_video_i386_vbeblit_replace_BGRX8888_RGBX8888 (target, source,
1022 x, y, width, height,
1023 offset_x, offset_y);
1024 return;
1026 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
1028 grub_video_i386_vbeblit_replace_BGR888_RGBX8888 (target, source,
1029 x, y, width, height,
1030 offset_x, offset_y);
1031 return;
1033 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
1035 grub_video_i386_vbeblit_replace_RGB888_RGBX8888 (target, source,
1036 x, y, width, height,
1037 offset_x, offset_y);
1038 return;
1040 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1042 grub_video_i386_vbeblit_replace_index_RGBX8888 (target, source,
1043 x, y, width, height,
1044 offset_x, offset_y);
1045 return;
1048 else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
1050 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
1052 grub_video_i386_vbeblit_replace_BGRX8888_RGB888 (target, source,
1053 x, y, width, height,
1054 offset_x, offset_y);
1055 return;
1057 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
1059 grub_video_i386_vbeblit_replace_RGBX8888_RGB888 (target, source,
1060 x, y, width, height,
1061 offset_x, offset_y);
1062 return;
1064 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
1066 grub_video_i386_vbeblit_replace_BGR888_RGB888 (target, source,
1067 x, y, width, height,
1068 offset_x, offset_y);
1069 return;
1071 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
1073 grub_video_i386_vbeblit_replace_directN (target, source,
1074 x, y, width, height,
1075 offset_x, offset_y);
1076 return;
1078 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1080 grub_video_i386_vbeblit_replace_index_RGB888 (target, source,
1081 x, y, width, height,
1082 offset_x, offset_y);
1083 return;
1086 else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
1088 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
1090 grub_video_i386_vbeblit_replace_directN (target, source,
1091 x, y, width, height,
1092 offset_x, offset_y);
1093 return;
1096 else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1098 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1100 grub_video_i386_vbeblit_replace_directN (target, source,
1101 x, y, width, height,
1102 offset_x, offset_y);
1103 return;
1107 /* No optimized replace operator found, use default (slow) blitter. */
1108 grub_video_i386_vbeblit_replace (target, source, x, y, width, height,
1109 offset_x, offset_y);
1111 else
1113 /* Try to figure out more optimized blend operator. */
1114 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
1116 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
1118 grub_video_i386_vbeblit_blend_BGRA8888_RGBA8888 (target, source,
1119 x, y, width, height,
1120 offset_x, offset_y);
1121 return;
1123 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
1125 grub_video_i386_vbeblit_blend_RGBA8888_RGBA8888 (target, source,
1126 x, y, width, height,
1127 offset_x, offset_y);
1128 return;
1130 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
1132 grub_video_i386_vbeblit_blend_BGR888_RGBA8888 (target, source,
1133 x, y, width, height,
1134 offset_x, offset_y);
1135 return;
1137 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
1139 grub_video_i386_vbeblit_blend_RGB888_RGBA8888 (target, source,
1140 x, y, width, height,
1141 offset_x, offset_y);
1142 return;
1144 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1146 grub_video_i386_vbeblit_blend_index_RGBA8888 (target, source,
1147 x, y, width, height,
1148 offset_x, offset_y);
1149 return;
1152 else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
1154 /* Note: There is really no alpha information here, so blend is
1155 changed to replace. */
1157 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
1159 grub_video_i386_vbeblit_replace_BGRX8888_RGB888 (target, source,
1160 x, y, width, height,
1161 offset_x, offset_y);
1162 return;
1164 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
1166 grub_video_i386_vbeblit_replace_RGBX8888_RGB888 (target, source,
1167 x, y, width, height,
1168 offset_x, offset_y);
1169 return;
1171 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
1173 grub_video_i386_vbeblit_replace_BGR888_RGB888 (target, source,
1174 x, y, width, height,
1175 offset_x, offset_y);
1176 return;
1178 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
1180 grub_video_i386_vbeblit_replace_directN (target, source,
1181 x, y, width, height,
1182 offset_x, offset_y);
1183 return;
1185 else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1187 grub_video_i386_vbeblit_replace_index_RGB888 (target, source,
1188 x, y, width, height,
1189 offset_x, offset_y);
1190 return;
1194 /* No optimized blend operation found, use default (slow) blitter. */
1195 grub_video_i386_vbeblit_blend (target, source, x, y, width, height,
1196 offset_x, offset_y);
1200 static grub_err_t
1201 grub_video_vbe_blit_bitmap (struct grub_video_bitmap *bitmap,
1202 enum grub_video_blit_operators oper, int x, int y,
1203 int offset_x, int offset_y,
1204 unsigned int width, unsigned int height)
1206 struct grub_video_i386_vbeblit_info source;
1207 struct grub_video_i386_vbeblit_info target;
1209 /* Make sure there is something to do. */
1210 if ((width == 0) || (height == 0))
1211 return GRUB_ERR_NONE;
1212 if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0))
1213 return GRUB_ERR_NONE;
1214 if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0))
1215 return GRUB_ERR_NONE;
1216 if ((x + (int)bitmap->mode_info.width) < 0)
1217 return GRUB_ERR_NONE;
1218 if ((y + (int)bitmap->mode_info.height) < 0)
1219 return GRUB_ERR_NONE;
1220 if ((offset_x >= (int)bitmap->mode_info.width)
1221 || (offset_x + (int)width < 0))
1222 return GRUB_ERR_NONE;
1223 if ((offset_y >= (int)bitmap->mode_info.height)
1224 || (offset_y + (int)height < 0))
1225 return GRUB_ERR_NONE;
1227 /* If we have negative coordinates, optimize drawing to minimum. */
1228 if (offset_x < 0)
1230 width += offset_x;
1231 x -= offset_x;
1232 offset_x = 0;
1235 if (offset_y < 0)
1237 height += offset_y;
1238 y -= offset_y;
1239 offset_y = 0;
1242 if (x < 0)
1244 width += x;
1245 offset_x -= x;
1246 x = 0;
1249 if (y < 0)
1251 height += y;
1252 offset_y -= y;
1253 y = 0;
1256 /* Do not allow drawing out of viewport. */
1257 if ((x + width) > render_target->viewport.width)
1258 width = render_target->viewport.width - x;
1259 if ((y + height) > render_target->viewport.height)
1260 height = render_target->viewport.height - y;
1262 if ((offset_x + width) > bitmap->mode_info.width)
1263 width = bitmap->mode_info.width - offset_x;
1264 if ((offset_y + height) > bitmap->mode_info.height)
1265 height = bitmap->mode_info.height - offset_y;
1267 /* Limit drawing to source render target dimensions. */
1268 if (width > bitmap->mode_info.width)
1269 width = bitmap->mode_info.width;
1271 if (height > bitmap->mode_info.height)
1272 height = bitmap->mode_info.height;
1274 /* Add viewport offset. */
1275 x += render_target->viewport.x;
1276 y += render_target->viewport.y;
1278 /* Use vbeblit_info to encapsulate rendering. */
1279 source.mode_info = &bitmap->mode_info;
1280 source.data = bitmap->data;
1281 target.mode_info = &render_target->mode_info;
1282 target.data = render_target->data;
1284 /* Do actual blitting. */
1285 common_blitter (&target, &source, oper, x, y, width, height,
1286 offset_x, offset_y);
1288 return GRUB_ERR_NONE;
1291 static grub_err_t
1292 grub_video_vbe_blit_render_target (struct grub_video_render_target *source,
1293 enum grub_video_blit_operators oper,
1294 int x, int y, int offset_x, int offset_y,
1295 unsigned int width, unsigned int height)
1297 struct grub_video_i386_vbeblit_info source_info;
1298 struct grub_video_i386_vbeblit_info target_info;
1300 /* Make sure there is something to do. */
1301 if ((width == 0) || (height == 0))
1302 return GRUB_ERR_NONE;
1303 if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0))
1304 return GRUB_ERR_NONE;
1305 if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0))
1306 return GRUB_ERR_NONE;
1307 if ((x + (int)source->mode_info.width) < 0)
1308 return GRUB_ERR_NONE;
1309 if ((y + (int)source->mode_info.height) < 0)
1310 return GRUB_ERR_NONE;
1311 if ((offset_x >= (int)source->mode_info.width)
1312 || (offset_x + (int)width < 0))
1313 return GRUB_ERR_NONE;
1314 if ((offset_y >= (int)source->mode_info.height)
1315 || (offset_y + (int)height < 0))
1316 return GRUB_ERR_NONE;
1318 /* If we have negative coordinates, optimize drawing to minimum. */
1319 if (offset_x < 0)
1321 width += offset_x;
1322 x -= offset_x;
1323 offset_x = 0;
1326 if (offset_y < 0)
1328 height += offset_y;
1329 y -= offset_y;
1330 offset_y = 0;
1333 if (x < 0)
1335 width += x;
1336 offset_x -= x;
1337 x = 0;
1340 if (y < 0)
1342 height += y;
1343 offset_y -= y;
1344 y = 0;
1347 /* Do not allow drawing out of viewport. */
1348 if ((x + width) > render_target->viewport.width)
1349 width = render_target->viewport.width - x;
1350 if ((y + height) > render_target->viewport.height)
1351 height = render_target->viewport.height - y;
1353 if ((offset_x + width) > source->mode_info.width)
1354 width = source->mode_info.width - offset_x;
1355 if ((offset_y + height) > source->mode_info.height)
1356 height = source->mode_info.height - offset_y;
1358 /* Limit drawing to source render target dimensions. */
1359 if (width > source->mode_info.width)
1360 width = source->mode_info.width;
1362 if (height > source->mode_info.height)
1363 height = source->mode_info.height;
1365 /* Add viewport offset. */
1366 x += render_target->viewport.x;
1367 y += render_target->viewport.y;
1369 /* Use vbeblit_info to encapsulate rendering. */
1370 source_info.mode_info = &source->mode_info;
1371 source_info.data = source->data;
1372 target_info.mode_info = &render_target->mode_info;
1373 target_info.data = render_target->data;
1375 /* Do actual blitting. */
1376 common_blitter (&target_info, &source_info, oper, x, y, width, height,
1377 offset_x, offset_y);
1379 return GRUB_ERR_NONE;
1382 static grub_err_t
1383 grub_video_vbe_scroll (grub_video_color_t color, int dx, int dy)
1385 int width;
1386 int height;
1387 int src_x;
1388 int src_y;
1389 int dst_x;
1390 int dst_y;
1392 /* 1. Check if we have something to do. */
1393 if ((dx == 0) && (dy == 0))
1394 return GRUB_ERR_NONE;
1396 width = render_target->viewport.width - grub_abs (dx);
1397 height = render_target->viewport.height - grub_abs (dy);
1399 if (dx < 0)
1401 src_x = render_target->viewport.x - dx;
1402 dst_x = render_target->viewport.x;
1404 else
1406 src_x = render_target->viewport.x;
1407 dst_x = render_target->viewport.x + dx;
1410 if (dy < 0)
1412 src_y = render_target->viewport.y - dy;
1413 dst_y = render_target->viewport.y;
1415 else
1417 src_y = render_target->viewport.y;
1418 dst_y = render_target->viewport.y + dy;
1421 /* 2. Check if there is need to copy data. */
1422 if ((grub_abs (dx) < render_target->viewport.width)
1423 && (grub_abs (dy) < render_target->viewport.height))
1425 /* 3. Move data in render target. */
1426 struct grub_video_i386_vbeblit_info target;
1427 grub_uint8_t *src;
1428 grub_uint8_t *dst;
1429 int j;
1431 target.mode_info = &render_target->mode_info;
1432 target.data = render_target->data;
1434 for (j = 0; j < height; j++)
1436 dst = grub_video_vbe_get_video_ptr (&target, dst_x, dst_y + j);
1437 src = grub_video_vbe_get_video_ptr (&target, src_x, src_y + j);
1438 grub_memmove (dst, src,
1439 width * target.mode_info->bytes_per_pixel);
1443 /* 4. Fill empty space with specified color. In this implementation
1444 there might be colliding areas but at the moment there is no need
1445 to optimize this. */
1447 /* 4a. Fill top & bottom parts. */
1448 if (dy > 0)
1449 grub_video_vbe_fill_rect (color, 0, 0, render_target->viewport.width, dy);
1450 else if (dy < 0)
1452 if (render_target->viewport.height < grub_abs (dy))
1453 dy = -render_target->viewport.height;
1455 grub_video_vbe_fill_rect (color, 0, render_target->viewport.height + dy,
1456 render_target->viewport.width, -dy);
1459 /* 4b. Fill left & right parts. */
1460 if (dx > 0)
1461 grub_video_vbe_fill_rect (color, 0, 0,
1462 dx, render_target->viewport.height);
1463 else if (dx < 0)
1465 if (render_target->viewport.width < grub_abs (dx))
1466 dx = -render_target->viewport.width;
1468 grub_video_vbe_fill_rect (color, render_target->viewport.width + dx, 0,
1469 -dx, render_target->viewport.height);
1472 return GRUB_ERR_NONE;
1475 static grub_err_t
1476 grub_video_vbe_swap_buffers (void)
1478 /* TODO: Implement buffer swapping. */
1479 return GRUB_ERR_NONE;
1482 static grub_err_t
1483 grub_video_vbe_create_render_target (struct grub_video_render_target **result,
1484 unsigned int width, unsigned int height,
1485 unsigned int mode_type __attribute__ ((unused)))
1487 struct grub_video_render_target *target;
1488 unsigned int size;
1490 /* Validate arguments. */
1491 if ((! result)
1492 || (width == 0)
1493 || (height == 0))
1494 return grub_error (GRUB_ERR_BAD_ARGUMENT,
1495 "invalid argument given.");
1497 /* Allocate memory for render target. */
1498 target = grub_malloc (sizeof (struct grub_video_render_target));
1499 if (! target)
1500 return grub_errno;
1502 /* TODO: Implement other types too.
1503 Currently only 32bit render targets are supported. */
1505 /* Mark render target as allocated. */
1506 target->is_allocated = 1;
1508 /* Maximize viewport. */
1509 target->viewport.x = 0;
1510 target->viewport.y = 0;
1511 target->viewport.width = width;
1512 target->viewport.height = height;
1514 /* Setup render target format. */
1515 target->mode_info.width = width;
1516 target->mode_info.height = height;
1517 target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB
1518 | GRUB_VIDEO_MODE_TYPE_ALPHA;
1519 target->mode_info.bpp = 32;
1520 target->mode_info.bytes_per_pixel = 4;
1521 target->mode_info.pitch = target->mode_info.bytes_per_pixel * width;
1522 target->mode_info.number_of_colors = 256; /* Emulated palette. */
1523 target->mode_info.red_mask_size = 8;
1524 target->mode_info.red_field_pos = 0;
1525 target->mode_info.green_mask_size = 8;
1526 target->mode_info.green_field_pos = 8;
1527 target->mode_info.blue_mask_size = 8;
1528 target->mode_info.blue_field_pos = 16;
1529 target->mode_info.reserved_mask_size = 8;
1530 target->mode_info.reserved_field_pos = 24;
1532 target->mode_info.blit_format = grub_video_get_blit_format (&target->mode_info);
1534 /* Calculate size needed for the data. */
1535 size = (width * target->mode_info.bytes_per_pixel) * height;
1537 target->data = grub_malloc (size);
1538 if (! target->data)
1540 grub_free (target);
1541 return grub_errno;
1544 /* Clear render target with black and maximum transparency. */
1545 grub_memset (target->data, 0, size);
1547 /* TODO: Add render target to render target list. */
1549 /* Save result to caller. */
1550 *result = target;
1552 return GRUB_ERR_NONE;
1555 static grub_err_t
1556 grub_video_vbe_delete_render_target (struct grub_video_render_target *target)
1558 /* If there is no target, then just return without error. */
1559 if (! target)
1560 return GRUB_ERR_NONE;
1562 /* TODO: Delist render target fron render target list. */
1564 /* If this is software render target, free it's memory. */
1565 if (target->is_allocated)
1566 grub_free (target->data);
1568 /* Free render target. */
1569 grub_free (target);
1571 return GRUB_ERR_NONE;
1574 static grub_err_t
1575 grub_video_vbe_set_active_render_target (struct grub_video_render_target *target)
1577 if (target == GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER)
1579 render_target = &framebuffer.render_target;
1581 return GRUB_ERR_NONE;
1584 if (target == GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER)
1585 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1586 "double buffering not implemented yet.");
1588 if (! target->data)
1589 return grub_error (GRUB_ERR_BAD_ARGUMENT,
1590 "invalid render target given.");
1592 render_target = target;
1594 return GRUB_ERR_NONE;
1597 static grub_err_t
1598 grub_video_vbe_get_active_render_target (struct grub_video_render_target **target)
1600 *target = render_target;
1602 return GRUB_ERR_NONE;
1605 static struct grub_video_adapter grub_video_vbe_adapter =
1607 .name = "VESA BIOS Extension Video Driver",
1609 .init = grub_video_vbe_init,
1610 .fini = grub_video_vbe_fini,
1611 .setup = grub_video_vbe_setup,
1612 .get_info = grub_video_vbe_get_info,
1613 .set_palette = grub_video_vbe_set_palette,
1614 .get_palette = grub_video_vbe_get_palette,
1615 .set_viewport = grub_video_vbe_set_viewport,
1616 .get_viewport = grub_video_vbe_get_viewport,
1617 .map_color = grub_video_vbe_map_color,
1618 .map_rgb = grub_video_vbe_map_rgb,
1619 .map_rgba = grub_video_vbe_map_rgba,
1620 .unmap_color = grub_video_vbe_unmap_color,
1621 .fill_rect = grub_video_vbe_fill_rect,
1622 .blit_glyph = grub_video_vbe_blit_glyph,
1623 .blit_bitmap = grub_video_vbe_blit_bitmap,
1624 .blit_render_target = grub_video_vbe_blit_render_target,
1625 .scroll = grub_video_vbe_scroll,
1626 .swap_buffers = grub_video_vbe_swap_buffers,
1627 .create_render_target = grub_video_vbe_create_render_target,
1628 .delete_render_target = grub_video_vbe_delete_render_target,
1629 .set_active_render_target = grub_video_vbe_set_active_render_target,
1630 .get_active_render_target = grub_video_vbe_get_active_render_target,
1632 .next = 0
1635 GRUB_MOD_INIT(video_i386_pc_vbe)
1637 grub_video_register (&grub_video_vbe_adapter);
1640 GRUB_MOD_FINI(video_i386_pc_vbe)
1642 grub_video_unregister (&grub_video_vbe_adapter);