make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / video / i386 / pc / vbe.c
blobedd73d50d3320b88a3b500ac257034ca61d16244
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 static grub_video_color_t
650 grub_video_vbe_map_color (grub_uint32_t color_name)
652 /* TODO: implement color theme mapping code. */
654 if (color_name < 256)
656 if ((render_target->mode_info.mode_type
657 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
658 return color_name;
659 else
661 grub_video_color_t color;
663 color = grub_video_vbe_map_rgb (framebuffer.palette[color_name].r,
664 framebuffer.palette[color_name].g,
665 framebuffer.palette[color_name].b);
667 return color;
671 return 0;
674 grub_video_color_t
675 grub_video_vbe_map_rgb (grub_uint8_t red, grub_uint8_t green,
676 grub_uint8_t blue)
678 if ((render_target->mode_info.mode_type
679 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
681 int minindex = 0;
682 int delta = 0;
683 int tmp;
684 int val;
685 int i;
687 /* Find best matching color. */
688 for (i = 0; i < 256; i++)
690 val = framebuffer.palette[i].r - red;
691 tmp = val * val;
692 val = framebuffer.palette[i].g - green;
693 tmp += val * val;
694 val = framebuffer.palette[i].b - blue;
695 tmp += val * val;
697 if (i == 0)
698 delta = tmp;
700 if (tmp < delta)
702 delta = tmp;
703 minindex = i;
704 if (tmp == 0)
705 break;
709 return minindex;
711 else
713 grub_uint32_t value;
714 grub_uint8_t alpha = 255; /* Opaque color. */
716 red >>= 8 - render_target->mode_info.red_mask_size;
717 green >>= 8 - render_target->mode_info.green_mask_size;
718 blue >>= 8 - render_target->mode_info.blue_mask_size;
719 alpha >>= 8 - render_target->mode_info.reserved_mask_size;
721 value = red << render_target->mode_info.red_field_pos;
722 value |= green << render_target->mode_info.green_field_pos;
723 value |= blue << render_target->mode_info.blue_field_pos;
724 value |= alpha << render_target->mode_info.reserved_field_pos;
726 return value;
731 grub_video_color_t
732 grub_video_vbe_map_rgba (grub_uint8_t red, grub_uint8_t green,
733 grub_uint8_t blue, grub_uint8_t alpha)
735 if ((render_target->mode_info.mode_type
736 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
737 /* No alpha available in index color modes, just use
738 same value as in only RGB modes. */
739 return grub_video_vbe_map_rgb (red, green, blue);
740 else
742 grub_uint32_t value;
744 red >>= 8 - render_target->mode_info.red_mask_size;
745 green >>= 8 - render_target->mode_info.green_mask_size;
746 blue >>= 8 - render_target->mode_info.blue_mask_size;
747 alpha >>= 8 - render_target->mode_info.reserved_mask_size;
749 value = red << render_target->mode_info.red_field_pos;
750 value |= green << render_target->mode_info.green_field_pos;
751 value |= blue << render_target->mode_info.blue_field_pos;
752 value |= alpha << render_target->mode_info.reserved_field_pos;
754 return value;
758 grub_err_t grub_video_vbe_unmap_color (grub_video_color_t color,
759 grub_uint8_t *red, grub_uint8_t *green,
760 grub_uint8_t *blue, grub_uint8_t *alpha)
762 struct grub_video_i386_vbeblit_info target_info;
764 target_info.mode_info = &render_target->mode_info;
765 target_info.data = render_target->data;
767 grub_video_vbe_unmap_color_int (&target_info, color, red, green, blue, alpha);
769 return GRUB_ERR_NONE;
772 void
773 grub_video_vbe_unmap_color_int (struct grub_video_i386_vbeblit_info * source,
774 grub_video_color_t color,
775 grub_uint8_t *red, grub_uint8_t *green,
776 grub_uint8_t *blue, grub_uint8_t *alpha)
778 struct grub_video_mode_info *mode_info;
779 mode_info = source->mode_info;
781 if ((mode_info->mode_type
782 & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
784 /* If we have an out-of-bounds color, return transparent black. */
785 if (color > 255)
787 *red = 0;
788 *green = 0;
789 *blue = 0;
790 *alpha = 0;
791 return;
794 *red = framebuffer.palette[color].r;
795 *green = framebuffer.palette[color].g;
796 *blue = framebuffer.palette[color].b;
797 *alpha = framebuffer.palette[color].a;
798 return;
800 else
802 grub_uint32_t tmp;
804 /* Get red component. */
805 tmp = color >> mode_info->red_field_pos;
806 tmp &= (1 << mode_info->red_mask_size) - 1;
807 tmp <<= 8 - mode_info->red_mask_size;
808 tmp |= (1 << (8 - mode_info->red_mask_size)) - 1;
809 *red = tmp & 0xFF;
811 /* Get green component. */
812 tmp = color >> mode_info->green_field_pos;
813 tmp &= (1 << mode_info->green_mask_size) - 1;
814 tmp <<= 8 - mode_info->green_mask_size;
815 tmp |= (1 << (8 - mode_info->green_mask_size)) - 1;
816 *green = tmp & 0xFF;
818 /* Get blue component. */
819 tmp = color >> mode_info->blue_field_pos;
820 tmp &= (1 << mode_info->blue_mask_size) - 1;
821 tmp <<= 8 - mode_info->blue_mask_size;
822 tmp |= (1 << (8 - mode_info->blue_mask_size)) - 1;
823 *blue = tmp & 0xFF;
825 /* Get alpha component. */
826 if (source->mode_info->reserved_mask_size > 0)
828 tmp = color >> mode_info->reserved_field_pos;
829 tmp &= (1 << mode_info->reserved_mask_size) - 1;
830 tmp <<= 8 - mode_info->reserved_mask_size;
831 tmp |= (1 << (8 - mode_info->reserved_mask_size)) - 1;
833 else
834 /* If there is no alpha component, assume it opaque. */
835 tmp = 255;
837 *alpha = tmp & 0xFF;
841 static grub_err_t
842 grub_video_vbe_fill_rect (grub_video_color_t color, int x, int y,
843 unsigned int width, unsigned int height)
845 struct grub_video_i386_vbeblit_info target;
847 /* Make sure there is something to do. */
848 if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0))
849 return GRUB_ERR_NONE;
850 if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0))
851 return GRUB_ERR_NONE;
853 /* Do not allow drawing out of viewport. */
854 if (x < 0)
856 width += x;
857 x = 0;
859 if (y < 0)
861 height += y;
862 y = 0;
865 if ((x + width) > render_target->viewport.width)
866 width = render_target->viewport.width - x;
867 if ((y + height) > render_target->viewport.height)
868 height = render_target->viewport.height - y;
870 /* Add viewport offset. */
871 x += render_target->viewport.x;
872 y += render_target->viewport.y;
874 /* Use vbeblit_info to encapsulate rendering. */
875 target.mode_info = &render_target->mode_info;
876 target.data = render_target->data;
878 /* Try to figure out more optimized version. */
879 if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
881 grub_video_i386_vbefill_R8G8B8A8 (&target, color, x, y,
882 width, height);
883 return GRUB_ERR_NONE;
886 if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
888 grub_video_i386_vbefill_R8G8B8 (&target, color, x, y,
889 width, height);
890 return GRUB_ERR_NONE;
893 if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
895 grub_video_i386_vbefill_index (&target, color, x, y,
896 width, height);
897 return GRUB_ERR_NONE;
900 /* No optimized version found, use default (slow) filler. */
901 grub_video_i386_vbefill (&target, color, x, y, width, height);
903 return GRUB_ERR_NONE;
906 // TODO: Remove this method and replace with bitmap based glyphs
907 static grub_err_t
908 grub_video_vbe_blit_glyph (struct grub_font_glyph * glyph,
909 grub_video_color_t color, int x, int y)
911 struct grub_video_i386_vbeblit_info target;
912 unsigned int width;
913 unsigned int charwidth;
914 unsigned int height;
915 unsigned int i;
916 unsigned int j;
917 unsigned int x_offset = 0;
918 unsigned int y_offset = 0;
920 /* Make sure there is something to do. */
921 if (x >= (int)render_target->viewport.width)
922 return GRUB_ERR_NONE;
924 if (y >= (int)render_target->viewport.height)
925 return GRUB_ERR_NONE;
927 /* Calculate glyph dimensions. */
928 width = ((glyph->width + 7) / 8) * 8;
929 charwidth = width;
930 height = glyph->height;
932 if (x + (int)width < 0)
933 return GRUB_ERR_NONE;
935 if (y + (int)height < 0)
936 return GRUB_ERR_NONE;
938 /* Do not allow drawing out of viewport. */
939 if (x < 0)
941 width += x;
942 x_offset = (unsigned int)-x;
943 x = 0;
945 if (y < 0)
947 height += y;
948 y_offset = (unsigned int)-y;
949 y = 0;
952 if ((x + width) > render_target->viewport.width)
953 width = render_target->viewport.width - x;
954 if ((y + height) > render_target->viewport.height)
955 height = render_target->viewport.height - y;
957 /* Add viewport offset. */
958 x += render_target->viewport.x;
959 y += render_target->viewport.y;
961 /* Use vbeblit_info to encapsulate rendering. */
962 target.mode_info = &render_target->mode_info;
963 target.data = render_target->data;
965 /* Draw glyph. */
966 for (j = 0; j < height; j++)
967 for (i = 0; i < width; i++)
968 if ((glyph->bitmap[((i + x_offset) / 8)
969 + (j + y_offset) * (charwidth / 8)]
970 & (1 << ((charwidth - (i + x_offset) - 1) % 8))))
971 set_pixel (&target, x+i, y+j, color);
973 return GRUB_ERR_NONE;
976 /* NOTE: This function assumes that given coordinates are within bounds of
977 handled data. */
978 static void
979 common_blitter (struct grub_video_i386_vbeblit_info *target,
980 struct grub_video_i386_vbeblit_info *source,
981 enum grub_video_blit_operators oper, int x, int y,
982 unsigned int width, unsigned int height,
983 int offset_x, int offset_y)
985 if (oper == GRUB_VIDEO_BLIT_REPLACE)
987 /* Try to figure out more optimized version for replace operator. */
988 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
990 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
992 grub_video_i386_vbeblit_R8G8B8X8_R8G8B8X8 (target, source,
993 x, y, width, height,
994 offset_x, offset_y);
995 return;
998 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
1000 grub_video_i386_vbeblit_R8G8B8_R8G8B8X8 (target, source,
1001 x, y, width, height,
1002 offset_x, offset_y);
1003 return;
1006 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1008 grub_video_i386_vbeblit_index_R8G8B8X8 (target, source,
1009 x, y, width, height,
1010 offset_x, offset_y);
1011 return;
1015 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
1017 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
1019 grub_video_i386_vbeblit_R8G8B8A8_R8G8B8 (target, source,
1020 x, y, width, height,
1021 offset_x, offset_y);
1022 return;
1025 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
1027 grub_video_i386_vbeblit_R8G8B8_R8G8B8 (target, source,
1028 x, y, width, height,
1029 offset_x, offset_y);
1030 return;
1033 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1035 grub_video_i386_vbeblit_index_R8G8B8 (target, source,
1036 x, y, width, height,
1037 offset_x, offset_y);
1038 return;
1042 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1044 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1046 grub_video_i386_vbeblit_index_index (target, source,
1047 x, y, width, height,
1048 offset_x, offset_y);
1049 return;
1053 /* No optimized replace operator found, use default (slow) blitter. */
1054 grub_video_i386_vbeblit_replace (target, source, x, y, width, height,
1055 offset_x, offset_y);
1057 else
1059 /* Try to figure out more optimized blend operator. */
1060 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
1062 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
1064 grub_video_i386_vbeblit_R8G8B8A8_R8G8B8A8 (target, source,
1065 x, y, width, height,
1066 offset_x, offset_y);
1067 return;
1070 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
1072 grub_video_i386_vbeblit_R8G8B8_R8G8B8A8 (target, source,
1073 x, y, width, height,
1074 offset_x, offset_y);
1075 return;
1078 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1080 grub_video_i386_vbeblit_index_R8G8B8A8 (target, source,
1081 x, y, width, height,
1082 offset_x, offset_y);
1083 return;
1087 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
1089 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
1091 grub_video_i386_vbeblit_R8G8B8A8_R8G8B8 (target, source,
1092 x, y, width, height,
1093 offset_x, offset_y);
1094 return;
1097 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
1099 grub_video_i386_vbeblit_R8G8B8_R8G8B8 (target, source,
1100 x, y, width, height,
1101 offset_x, offset_y);
1102 return;
1105 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1107 grub_video_i386_vbeblit_index_R8G8B8 (target, source,
1108 x, y, width, height,
1109 offset_x, offset_y);
1110 return;
1114 if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1116 if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
1118 grub_video_i386_vbeblit_index_index (target, source,
1119 x, y, width, height,
1120 offset_x, offset_y);
1121 return;
1125 /* No optimized blend operation found, use default (slow) blitter. */
1126 grub_video_i386_vbeblit_blend (target, source, x, y, width, height,
1127 offset_x, offset_y);
1131 static grub_err_t
1132 grub_video_vbe_blit_bitmap (struct grub_video_bitmap *bitmap,
1133 enum grub_video_blit_operators oper, int x, int y,
1134 int offset_x, int offset_y,
1135 unsigned int width, unsigned int height)
1137 struct grub_video_i386_vbeblit_info source;
1138 struct grub_video_i386_vbeblit_info target;
1140 /* Make sure there is something to do. */
1141 if ((width == 0) || (height == 0))
1142 return GRUB_ERR_NONE;
1143 if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0))
1144 return GRUB_ERR_NONE;
1145 if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0))
1146 return GRUB_ERR_NONE;
1147 if ((x + (int)bitmap->mode_info.width) < 0)
1148 return GRUB_ERR_NONE;
1149 if ((y + (int)bitmap->mode_info.height) < 0)
1150 return GRUB_ERR_NONE;
1151 if ((offset_x >= (int)bitmap->mode_info.width)
1152 || (offset_x + (int)width < 0))
1153 return GRUB_ERR_NONE;
1154 if ((offset_y >= (int)bitmap->mode_info.height)
1155 || (offset_y + (int)height < 0))
1156 return GRUB_ERR_NONE;
1158 /* If we have negative coordinates, optimize drawing to minimum. */
1159 if (offset_x < 0)
1161 width += offset_x;
1162 x -= offset_x;
1163 offset_x = 0;
1166 if (offset_y < 0)
1168 height += offset_y;
1169 y -= offset_y;
1170 offset_y = 0;
1173 if (x < 0)
1175 width += x;
1176 offset_x -= x;
1177 x = 0;
1180 if (y < 0)
1182 height += y;
1183 offset_y -= y;
1184 y = 0;
1187 /* Do not allow drawing out of viewport. */
1188 if ((x + width) > render_target->viewport.width)
1189 width = render_target->viewport.width - x;
1190 if ((y + height) > render_target->viewport.height)
1191 height = render_target->viewport.height - y;
1193 if ((offset_x + width) > bitmap->mode_info.width)
1194 width = bitmap->mode_info.width - offset_x;
1195 if ((offset_y + height) > bitmap->mode_info.height)
1196 height = bitmap->mode_info.height - offset_y;
1198 /* Limit drawing to source render target dimensions. */
1199 if (width > bitmap->mode_info.width)
1200 width = bitmap->mode_info.width;
1202 if (height > bitmap->mode_info.height)
1203 height = bitmap->mode_info.height;
1205 /* Add viewport offset. */
1206 x += render_target->viewport.x;
1207 y += render_target->viewport.y;
1209 /* Use vbeblit_info to encapsulate rendering. */
1210 source.mode_info = &bitmap->mode_info;
1211 source.data = bitmap->data;
1212 target.mode_info = &render_target->mode_info;
1213 target.data = render_target->data;
1215 /* Do actual blitting. */
1216 common_blitter (&target, &source, oper, x, y, width, height,
1217 offset_x, offset_y);
1219 return GRUB_ERR_NONE;
1222 static grub_err_t
1223 grub_video_vbe_blit_render_target (struct grub_video_render_target *source,
1224 enum grub_video_blit_operators oper,
1225 int x, int y, int offset_x, int offset_y,
1226 unsigned int width, unsigned int height)
1228 struct grub_video_i386_vbeblit_info source_info;
1229 struct grub_video_i386_vbeblit_info target_info;
1231 /* Make sure there is something to do. */
1232 if ((width == 0) || (height == 0))
1233 return GRUB_ERR_NONE;
1234 if ((x >= (int)render_target->viewport.width) || (x + (int)width < 0))
1235 return GRUB_ERR_NONE;
1236 if ((y >= (int)render_target->viewport.height) || (y + (int)height < 0))
1237 return GRUB_ERR_NONE;
1238 if ((x + (int)source->mode_info.width) < 0)
1239 return GRUB_ERR_NONE;
1240 if ((y + (int)source->mode_info.height) < 0)
1241 return GRUB_ERR_NONE;
1242 if ((offset_x >= (int)source->mode_info.width)
1243 || (offset_x + (int)width < 0))
1244 return GRUB_ERR_NONE;
1245 if ((offset_y >= (int)source->mode_info.height)
1246 || (offset_y + (int)height < 0))
1247 return GRUB_ERR_NONE;
1249 /* If we have negative coordinates, optimize drawing to minimum. */
1250 if (offset_x < 0)
1252 width += offset_x;
1253 x -= offset_x;
1254 offset_x = 0;
1257 if (offset_y < 0)
1259 height += offset_y;
1260 y -= offset_y;
1261 offset_y = 0;
1264 if (x < 0)
1266 width += x;
1267 offset_x -= x;
1268 x = 0;
1271 if (y < 0)
1273 height += y;
1274 offset_y -= y;
1275 y = 0;
1278 /* Do not allow drawing out of viewport. */
1279 if ((x + width) > render_target->viewport.width)
1280 width = render_target->viewport.width - x;
1281 if ((y + height) > render_target->viewport.height)
1282 height = render_target->viewport.height - y;
1284 if ((offset_x + width) > source->mode_info.width)
1285 width = source->mode_info.width - offset_x;
1286 if ((offset_y + height) > source->mode_info.height)
1287 height = source->mode_info.height - offset_y;
1289 /* Limit drawing to source render target dimensions. */
1290 if (width > source->mode_info.width)
1291 width = source->mode_info.width;
1293 if (height > source->mode_info.height)
1294 height = source->mode_info.height;
1296 /* Add viewport offset. */
1297 x += render_target->viewport.x;
1298 y += render_target->viewport.y;
1300 /* Use vbeblit_info to encapsulate rendering. */
1301 source_info.mode_info = &source->mode_info;
1302 source_info.data = source->data;
1303 target_info.mode_info = &render_target->mode_info;
1304 target_info.data = render_target->data;
1306 /* Do actual blitting. */
1307 common_blitter (&target_info, &source_info, oper, x, y, width, height,
1308 offset_x, offset_y);
1310 return GRUB_ERR_NONE;
1313 static grub_err_t
1314 grub_video_vbe_scroll (grub_video_color_t color, int dx, int dy)
1316 int width;
1317 int height;
1318 int src_x;
1319 int src_y;
1320 int dst_x;
1321 int dst_y;
1323 /* 1. Check if we have something to do. */
1324 if ((dx == 0) && (dy == 0))
1325 return GRUB_ERR_NONE;
1327 width = render_target->viewport.width - grub_abs (dx);
1328 height = render_target->viewport.height - grub_abs (dy);
1330 if (dx < 0)
1332 src_x = render_target->viewport.x - dx;
1333 dst_x = render_target->viewport.x;
1335 else
1337 src_x = render_target->viewport.x;
1338 dst_x = render_target->viewport.x + dx;
1341 if (dy < 0)
1343 src_y = render_target->viewport.y - dy;
1344 dst_y = render_target->viewport.y;
1346 else
1348 src_y = render_target->viewport.y;
1349 dst_y = render_target->viewport.y + dy;
1352 /* 2. Check if there is need to copy data. */
1353 if ((grub_abs (dx) < render_target->viewport.width)
1354 && (grub_abs (dy) < render_target->viewport.height))
1356 /* 3. Move data in render target. */
1357 struct grub_video_i386_vbeblit_info target;
1358 grub_uint8_t *src;
1359 grub_uint8_t *dst;
1360 int j;
1362 target.mode_info = &render_target->mode_info;
1363 target.data = render_target->data;
1365 for (j = 0; j < height; j++)
1367 dst = grub_video_vbe_get_video_ptr (&target, dst_x, dst_y + j);
1368 src = grub_video_vbe_get_video_ptr (&target, src_x, src_y + j);
1369 grub_memmove (dst, src,
1370 width * target.mode_info->bytes_per_pixel);
1374 /* 4. Fill empty space with specified color. In this implementation
1375 there might be colliding areas but at the moment there is no need
1376 to optimize this. */
1378 /* 4a. Fill top & bottom parts. */
1379 if (dy > 0)
1380 grub_video_vbe_fill_rect (color, 0, 0, render_target->viewport.width, dy);
1381 else if (dy < 0)
1383 if (render_target->viewport.height < grub_abs (dy))
1384 dy = -render_target->viewport.height;
1386 grub_video_vbe_fill_rect (color, 0, render_target->viewport.height + dy,
1387 render_target->viewport.width, -dy);
1390 /* 4b. Fill left & right parts. */
1391 if (dx > 0)
1392 grub_video_vbe_fill_rect (color, 0, 0,
1393 dx, render_target->viewport.height);
1394 else if (dx < 0)
1396 if (render_target->viewport.width < grub_abs (dx))
1397 dx = -render_target->viewport.width;
1399 grub_video_vbe_fill_rect (color, render_target->viewport.width + dx, 0,
1400 -dx, render_target->viewport.height);
1403 return GRUB_ERR_NONE;
1406 static grub_err_t
1407 grub_video_vbe_swap_buffers (void)
1409 /* TODO: Implement buffer swapping. */
1410 return GRUB_ERR_NONE;
1413 static grub_err_t
1414 grub_video_vbe_create_render_target (struct grub_video_render_target **result,
1415 unsigned int width, unsigned int height,
1416 unsigned int mode_type __attribute__ ((unused)))
1418 struct grub_video_render_target *target;
1419 unsigned int size;
1421 /* Validate arguments. */
1422 if ((! result)
1423 || (width == 0)
1424 || (height == 0))
1425 return grub_error (GRUB_ERR_BAD_ARGUMENT,
1426 "invalid argument given.");
1428 /* Allocate memory for render target. */
1429 target = grub_malloc (sizeof (struct grub_video_render_target));
1430 if (! target)
1431 return grub_errno;
1433 /* TODO: Implement other types too.
1434 Currently only 32bit render targets are supported. */
1436 /* Mark render target as allocated. */
1437 target->is_allocated = 1;
1439 /* Maximize viewport. */
1440 target->viewport.x = 0;
1441 target->viewport.y = 0;
1442 target->viewport.width = width;
1443 target->viewport.height = height;
1445 /* Setup render target format. */
1446 target->mode_info.width = width;
1447 target->mode_info.height = height;
1448 target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB
1449 | GRUB_VIDEO_MODE_TYPE_ALPHA;
1450 target->mode_info.bpp = 32;
1451 target->mode_info.bytes_per_pixel = 4;
1452 target->mode_info.pitch = target->mode_info.bytes_per_pixel * width;
1453 target->mode_info.number_of_colors = 256; /* Emulated palette. */
1454 target->mode_info.red_mask_size = 8;
1455 target->mode_info.red_field_pos = 0;
1456 target->mode_info.green_mask_size = 8;
1457 target->mode_info.green_field_pos = 8;
1458 target->mode_info.blue_mask_size = 8;
1459 target->mode_info.blue_field_pos = 16;
1460 target->mode_info.reserved_mask_size = 8;
1461 target->mode_info.reserved_field_pos = 24;
1463 target->mode_info.blit_format = grub_video_get_blit_format (&target->mode_info);
1465 /* Calculate size needed for the data. */
1466 size = (width * target->mode_info.bytes_per_pixel) * height;
1468 target->data = grub_malloc (size);
1469 if (! target->data)
1471 grub_free (target);
1472 return grub_errno;
1475 /* Clear render target with black and maximum transparency. */
1476 grub_memset (target->data, 0, size);
1478 /* TODO: Add render target to render target list. */
1480 /* Save result to caller. */
1481 *result = target;
1483 return GRUB_ERR_NONE;
1486 static grub_err_t
1487 grub_video_vbe_delete_render_target (struct grub_video_render_target *target)
1489 /* If there is no target, then just return without error. */
1490 if (! target)
1491 return GRUB_ERR_NONE;
1493 /* TODO: Delist render target fron render target list. */
1495 /* If this is software render target, free it's memory. */
1496 if (target->is_allocated)
1497 grub_free (target->data);
1499 /* Free render target. */
1500 grub_free (target);
1502 return GRUB_ERR_NONE;
1505 static grub_err_t
1506 grub_video_vbe_set_active_render_target (struct grub_video_render_target *target)
1508 if (target == GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER)
1510 render_target = &framebuffer.render_target;
1512 return GRUB_ERR_NONE;
1515 if (target == GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER)
1516 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1517 "double buffering not implemented yet.");
1519 if (! target->data)
1520 return grub_error (GRUB_ERR_BAD_ARGUMENT,
1521 "invalid render target given.");
1523 render_target = target;
1525 return GRUB_ERR_NONE;
1528 static grub_err_t
1529 grub_video_vbe_get_active_render_target (struct grub_video_render_target **target)
1531 *target = render_target;
1533 return GRUB_ERR_NONE;
1536 static struct grub_video_adapter grub_video_vbe_adapter =
1538 .name = "VESA BIOS Extension Video Driver",
1540 .init = grub_video_vbe_init,
1541 .fini = grub_video_vbe_fini,
1542 .setup = grub_video_vbe_setup,
1543 .get_info = grub_video_vbe_get_info,
1544 .set_palette = grub_video_vbe_set_palette,
1545 .get_palette = grub_video_vbe_get_palette,
1546 .set_viewport = grub_video_vbe_set_viewport,
1547 .get_viewport = grub_video_vbe_get_viewport,
1548 .map_color = grub_video_vbe_map_color,
1549 .map_rgb = grub_video_vbe_map_rgb,
1550 .map_rgba = grub_video_vbe_map_rgba,
1551 .unmap_color = grub_video_vbe_unmap_color,
1552 .fill_rect = grub_video_vbe_fill_rect,
1553 .blit_glyph = grub_video_vbe_blit_glyph,
1554 .blit_bitmap = grub_video_vbe_blit_bitmap,
1555 .blit_render_target = grub_video_vbe_blit_render_target,
1556 .scroll = grub_video_vbe_scroll,
1557 .swap_buffers = grub_video_vbe_swap_buffers,
1558 .create_render_target = grub_video_vbe_create_render_target,
1559 .delete_render_target = grub_video_vbe_delete_render_target,
1560 .set_active_render_target = grub_video_vbe_set_active_render_target,
1561 .get_active_render_target = grub_video_vbe_get_active_render_target,
1563 .next = 0
1566 GRUB_MOD_INIT(video_i386_pc_vbe)
1568 grub_video_register (&grub_video_vbe_adapter);
1571 GRUB_MOD_FINI(video_i386_pc_vbe)
1573 grub_video_unregister (&grub_video_vbe_adapter);