~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to video/fb/video_fb.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  GRUB  --  GRand Unified Bootloader
3
 
 *  Copyright (C) 2005,2006,2007,2008,2009  Free Software Foundation, Inc.
4
 
 *
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.
9
 
 *
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.
14
 
 *
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/>.
17
 
 */
18
 
 
19
 
#include <grub/video.h>
20
 
#include <grub/video_fb.h>
21
 
#include <grub/misc.h>
22
 
#include <grub/mm.h>
23
 
#include <grub/fbblit.h>
24
 
#include <grub/fbfill.h>
25
 
#include <grub/fbutil.h>
26
 
#include <grub/bitmap.h>
27
 
 
28
 
static struct
29
 
{
30
 
  struct grub_video_fbrender_target *render_target;
31
 
  struct grub_video_fbrender_target *front_target;
32
 
  struct grub_video_fbrender_target *back_target;
33
 
  struct grub_video_palette_data *palette;
34
 
  unsigned int palette_size;
35
 
  /* For page flipping strategy.  */
36
 
  int displayed_page;           /* The page # that is the front buffer.  */
37
 
  int render_page;              /* The page # that is the back buffer.  */
38
 
  grub_video_fb_set_page_t set_page;
39
 
  char *offscreen_buffer;
40
 
  grub_video_fb_doublebuf_update_screen_t update_screen;
41
 
} framebuffer;
42
 
 
43
 
/* Specify "standard" VGA palette, some video cards may
44
 
   need this and this will also be used when using RGB modes.  */
45
 
struct grub_video_palette_data grub_video_fbstd_colors[GRUB_VIDEO_FBSTD_NUMCOLORS] =
46
 
  {
47
 
    // {R, G, B, A}
48
 
    {0x00, 0x00, 0x00, 0xFF}, // 0 = black
49
 
    {0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
50
 
    {0x00, 0xA8, 0x00, 0xFF}, // 2 = green
51
 
    {0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
52
 
    {0xA8, 0x00, 0x00, 0xFF}, // 4 = red
53
 
    {0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
54
 
    {0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
55
 
    {0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
56
 
 
57
 
    {0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
58
 
    {0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
59
 
    {0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
60
 
    {0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
61
 
    {0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
62
 
    {0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
63
 
    {0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
64
 
    {0xFE, 0xFE, 0xFE, 0xFF}  // 15 = white
65
 
  };
66
 
 
67
 
grub_err_t
68
 
grub_video_fb_init (void)
69
 
{
70
 
  grub_free (framebuffer.palette);
71
 
  framebuffer.render_target = 0;
72
 
  framebuffer.front_target = 0;
73
 
  framebuffer.back_target = 0;
74
 
  framebuffer.palette = 0;
75
 
  framebuffer.palette_size = 0;
76
 
  framebuffer.set_page = 0;
77
 
  return GRUB_ERR_NONE;
78
 
}
79
 
 
80
 
grub_err_t
81
 
grub_video_fb_fini (void)
82
 
{
83
 
  /* TODO: destroy render targets.  */
84
 
 
85
 
  grub_free (framebuffer.offscreen_buffer);
86
 
  grub_free (framebuffer.palette);
87
 
  framebuffer.render_target = 0;
88
 
  framebuffer.front_target = 0;
89
 
  framebuffer.back_target = 0;
90
 
  framebuffer.palette = 0;
91
 
  framebuffer.palette_size = 0;
92
 
  framebuffer.set_page = 0;
93
 
  framebuffer.offscreen_buffer = 0;
94
 
  return GRUB_ERR_NONE;
95
 
}
96
 
 
97
 
grub_err_t
98
 
grub_video_fb_get_info (struct grub_video_mode_info *mode_info)
99
 
{
100
 
  /* Copy mode info from active render target.  */
101
 
  grub_memcpy (mode_info, &framebuffer.render_target->mode_info,
102
 
               sizeof (struct grub_video_mode_info));
103
 
 
104
 
  return GRUB_ERR_NONE;
105
 
}
106
 
 
107
 
grub_err_t
108
 
grub_video_fb_get_palette (unsigned int start, unsigned int count,
109
 
                           struct grub_video_palette_data *palette_data)
110
 
{
111
 
  unsigned int i;
112
 
 
113
 
  /* Assume that we know everything from index color palette.  */
114
 
  for (i = 0; (i < count) && ((i + start) < framebuffer.palette_size); i++)
115
 
    palette_data[i] = framebuffer.palette[start + i];
116
 
 
117
 
  return GRUB_ERR_NONE;
118
 
}
119
 
 
120
 
grub_err_t
121
 
grub_video_fb_set_palette (unsigned int start, unsigned int count,
122
 
                           struct grub_video_palette_data *palette_data)
123
 
{
124
 
  unsigned i;
125
 
  if (start + count > framebuffer.palette_size)
126
 
    {
127
 
      framebuffer.palette_size = start + count;
128
 
      framebuffer.palette = grub_realloc (framebuffer.palette,
129
 
                                          sizeof (framebuffer.palette[0])
130
 
                                          * framebuffer.palette_size);
131
 
      if (!framebuffer.palette)
132
 
        {
133
 
          grub_video_fb_fini ();
134
 
          return grub_errno;
135
 
        }
136
 
    }
137
 
  for (i = 0; (i < count) && ((i + start) < framebuffer.palette_size); i++)
138
 
    framebuffer.palette[start + i] = palette_data[i];
139
 
  return GRUB_ERR_NONE;
140
 
}
141
 
 
142
 
grub_err_t
143
 
grub_video_fb_set_viewport (unsigned int x, unsigned int y,
144
 
                            unsigned int width, unsigned int height)
145
 
{
146
 
  /* Make sure viewport is withing screen dimensions.  If viewport was set
147
 
     to be out of the region, mark its size as zero.  */
148
 
  if (x > framebuffer.render_target->mode_info.width)
149
 
    {
150
 
      x = 0;
151
 
      width = 0;
152
 
    }
153
 
 
154
 
  if (y > framebuffer.render_target->mode_info.height)
155
 
    {
156
 
      y = 0;
157
 
      height = 0;
158
 
    }
159
 
 
160
 
  if (x + width > framebuffer.render_target->mode_info.width)
161
 
    width = framebuffer.render_target->mode_info.width - x;
162
 
 
163
 
  if (y + height > framebuffer.render_target->mode_info.height)
164
 
    height = framebuffer.render_target->mode_info.height - y;
165
 
 
166
 
  framebuffer.render_target->viewport.x = x;
167
 
  framebuffer.render_target->viewport.y = y;
168
 
  framebuffer.render_target->viewport.width = width;
169
 
  framebuffer.render_target->viewport.height = height;
170
 
 
171
 
  return GRUB_ERR_NONE;
172
 
}
173
 
 
174
 
grub_err_t
175
 
grub_video_fb_get_viewport (unsigned int *x, unsigned int *y,
176
 
                            unsigned int *width, unsigned int *height)
177
 
{
178
 
  if (x) *x = framebuffer.render_target->viewport.x;
179
 
  if (y) *y = framebuffer.render_target->viewport.y;
180
 
  if (width) *width = framebuffer.render_target->viewport.width;
181
 
  if (height) *height = framebuffer.render_target->viewport.height;
182
 
 
183
 
  return GRUB_ERR_NONE;
184
 
}
185
 
 
186
 
/* Maps color name to target optimized color format.  */
187
 
grub_video_color_t
188
 
grub_video_fb_map_color (grub_uint32_t color_name)
189
 
{
190
 
  /* TODO: implement color theme mapping code.  */
191
 
 
192
 
  if (color_name < framebuffer.palette_size)
193
 
    {
194
 
      if ((framebuffer.render_target->mode_info.mode_type
195
 
           & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
196
 
        return color_name;
197
 
      else
198
 
        {
199
 
          grub_video_color_t color;
200
 
 
201
 
          color = grub_video_fb_map_rgb (framebuffer.palette[color_name].r,
202
 
                                         framebuffer.palette[color_name].g,
203
 
                                         framebuffer.palette[color_name].b);
204
 
 
205
 
          return color;
206
 
        }
207
 
    }
208
 
 
209
 
  return 0;
210
 
}
211
 
 
212
 
/* Maps RGB to target optimized color format.  */
213
 
grub_video_color_t
214
 
grub_video_fb_map_rgb (grub_uint8_t red, grub_uint8_t green,
215
 
                       grub_uint8_t blue)
216
 
{
217
 
  if ((framebuffer.render_target->mode_info.mode_type
218
 
       & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
219
 
    {
220
 
      int minindex = 0;
221
 
      int delta = 0;
222
 
      int tmp;
223
 
      int val;
224
 
      unsigned i;
225
 
 
226
 
      /* Find best matching color.  */
227
 
      for (i = 0; i < framebuffer.palette_size; i++)
228
 
        {
229
 
          val = framebuffer.palette[i].r - red;
230
 
          tmp = val * val;
231
 
          val = framebuffer.palette[i].g - green;
232
 
          tmp += val * val;
233
 
          val = framebuffer.palette[i].b - blue;
234
 
          tmp += val * val;
235
 
 
236
 
          if (i == 0)
237
 
            delta = tmp;
238
 
 
239
 
          if (tmp < delta)
240
 
            {
241
 
              delta = tmp;
242
 
              minindex = i;
243
 
              if (tmp == 0)
244
 
                break;
245
 
            }
246
 
        }
247
 
 
248
 
      return minindex;
249
 
    }
250
 
  else if ((framebuffer.render_target->mode_info.mode_type
251
 
            & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
252
 
    {
253
 
       if (red == framebuffer.render_target->mode_info.fg_red
254
 
           && green == framebuffer.render_target->mode_info.fg_green
255
 
           && blue == framebuffer.render_target->mode_info.fg_blue)
256
 
         return 1;
257
 
       else
258
 
         return 0;
259
 
    }
260
 
  else
261
 
    {
262
 
      grub_uint32_t value;
263
 
      grub_uint8_t alpha = 255; /* Opaque color.  */
264
 
 
265
 
      red >>= 8 - framebuffer.render_target->mode_info.red_mask_size;
266
 
      green >>= 8 - framebuffer.render_target->mode_info.green_mask_size;
267
 
      blue >>= 8 - framebuffer.render_target->mode_info.blue_mask_size;
268
 
      alpha >>= 8 - framebuffer.render_target->mode_info.reserved_mask_size;
269
 
 
270
 
      value = red << framebuffer.render_target->mode_info.red_field_pos;
271
 
      value |= green << framebuffer.render_target->mode_info.green_field_pos;
272
 
      value |= blue << framebuffer.render_target->mode_info.blue_field_pos;
273
 
      value |= alpha << framebuffer.render_target->mode_info.reserved_field_pos;
274
 
 
275
 
      return value;
276
 
    }
277
 
 
278
 
}
279
 
 
280
 
/* Maps RGBA to target optimized color format.  */
281
 
grub_video_color_t
282
 
grub_video_fb_map_rgba (grub_uint8_t red, grub_uint8_t green,
283
 
                        grub_uint8_t blue, grub_uint8_t alpha)
284
 
{
285
 
  if ((framebuffer.render_target->mode_info.mode_type
286
 
       & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
287
 
    /* No alpha available in index color modes, just use
288
 
       same value as in only RGB modes.  */
289
 
    return grub_video_fb_map_rgb (red, green, blue);
290
 
  else if ((framebuffer.render_target->mode_info.mode_type
291
 
            & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
292
 
    {
293
 
      if (red == framebuffer.render_target->mode_info.fg_red
294
 
          && green == framebuffer.render_target->mode_info.fg_green
295
 
          && blue == framebuffer.render_target->mode_info.fg_blue
296
 
          && alpha == framebuffer.render_target->mode_info.fg_alpha)
297
 
        return 1;
298
 
      else
299
 
        return 0;
300
 
    }
301
 
  else
302
 
    {
303
 
      grub_uint32_t value;
304
 
 
305
 
      red >>= 8 - framebuffer.render_target->mode_info.red_mask_size;
306
 
      green >>= 8 - framebuffer.render_target->mode_info.green_mask_size;
307
 
      blue >>= 8 - framebuffer.render_target->mode_info.blue_mask_size;
308
 
      alpha >>= 8 - framebuffer.render_target->mode_info.reserved_mask_size;
309
 
 
310
 
      value = red << framebuffer.render_target->mode_info.red_field_pos;
311
 
      value |= green << framebuffer.render_target->mode_info.green_field_pos;
312
 
      value |= blue << framebuffer.render_target->mode_info.blue_field_pos;
313
 
      value |= alpha << framebuffer.render_target->mode_info.reserved_field_pos;
314
 
 
315
 
      return value;
316
 
    }
317
 
}
318
 
 
319
 
/* Splits target optimized format to components.  */
320
 
grub_err_t
321
 
grub_video_fb_unmap_color (grub_video_color_t color,
322
 
                           grub_uint8_t *red, grub_uint8_t *green,
323
 
                           grub_uint8_t *blue, grub_uint8_t *alpha)
324
 
{
325
 
  struct grub_video_fbblit_info target_info;
326
 
 
327
 
  target_info.mode_info = &framebuffer.render_target->mode_info;
328
 
  target_info.data = framebuffer.render_target->data;
329
 
 
330
 
  grub_video_fb_unmap_color_int (&target_info, color, red, green, blue, alpha);
331
 
 
332
 
  return GRUB_ERR_NONE;
333
 
}
334
 
 
335
 
/* Splits color in source format to components.  */
336
 
void
337
 
grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source,
338
 
                               grub_video_color_t color,
339
 
                               grub_uint8_t *red, grub_uint8_t *green,
340
 
                               grub_uint8_t *blue, grub_uint8_t *alpha)
341
 
{
342
 
  struct grub_video_mode_info *mode_info;
343
 
  mode_info = source->mode_info;
344
 
 
345
 
  if ((mode_info->mode_type
346
 
       & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
347
 
    {
348
 
      /* If we have an out-of-bounds color, return transparent black.  */
349
 
      if (color > 255)
350
 
        {
351
 
          *red = 0;
352
 
          *green = 0;
353
 
          *blue = 0;
354
 
          *alpha = 0;
355
 
          return;
356
 
        }
357
 
 
358
 
      *red = framebuffer.palette[color].r;
359
 
      *green = framebuffer.palette[color].g;
360
 
      *blue = framebuffer.palette[color].b;
361
 
      *alpha = framebuffer.palette[color].a;
362
 
      return;
363
 
    }
364
 
  else if ((mode_info->mode_type
365
 
            & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
366
 
    {
367
 
      if (color & 1)
368
 
        {
369
 
          *red = mode_info->fg_red;
370
 
          *green = mode_info->fg_green;
371
 
          *blue = mode_info->fg_blue;
372
 
          *alpha = mode_info->fg_alpha;
373
 
        }
374
 
      else
375
 
        {
376
 
          *red = mode_info->bg_red;
377
 
          *green = mode_info->bg_green;
378
 
          *blue = mode_info->bg_blue;
379
 
          *alpha = mode_info->bg_alpha;
380
 
        }
381
 
    }
382
 
  else
383
 
    {
384
 
      grub_uint32_t tmp;
385
 
 
386
 
      /* Get red component.  */
387
 
      tmp = color >> mode_info->red_field_pos;
388
 
      tmp &= (1 << mode_info->red_mask_size) - 1;
389
 
      tmp <<= 8 - mode_info->red_mask_size;
390
 
      tmp |= (1 << (8 - mode_info->red_mask_size)) - 1;
391
 
      *red = tmp & 0xFF;
392
 
 
393
 
      /* Get green component.  */
394
 
      tmp = color >> mode_info->green_field_pos;
395
 
      tmp &= (1 << mode_info->green_mask_size) - 1;
396
 
      tmp <<= 8 - mode_info->green_mask_size;
397
 
      tmp |= (1 << (8 - mode_info->green_mask_size)) - 1;
398
 
      *green = tmp & 0xFF;
399
 
 
400
 
      /* Get blue component.  */
401
 
      tmp = color >> mode_info->blue_field_pos;
402
 
      tmp &= (1 << mode_info->blue_mask_size) - 1;
403
 
      tmp <<= 8 - mode_info->blue_mask_size;
404
 
      tmp |= (1 << (8 - mode_info->blue_mask_size)) - 1;
405
 
      *blue = tmp & 0xFF;
406
 
 
407
 
      /* Get alpha component.  */
408
 
      if (source->mode_info->reserved_mask_size > 0)
409
 
        {
410
 
          tmp = color >> mode_info->reserved_field_pos;
411
 
          tmp &= (1 << mode_info->reserved_mask_size) - 1;
412
 
          tmp <<= 8 - mode_info->reserved_mask_size;
413
 
          tmp |= (1 << (8 - mode_info->reserved_mask_size)) - 1;
414
 
        }
415
 
      else
416
 
        /* If there is no alpha component, assume it opaque.  */
417
 
        tmp = 255;
418
 
 
419
 
      *alpha = tmp & 0xFF;
420
 
    }
421
 
}
422
 
 
423
 
grub_err_t
424
 
grub_video_fb_fill_rect (grub_video_color_t color, int x, int y,
425
 
                         unsigned int width, unsigned int height)
426
 
{
427
 
  struct grub_video_fbblit_info target;
428
 
 
429
 
  /* Make sure there is something to do.  */
430
 
  if ((x >= (int)framebuffer.render_target->viewport.width) || (x + (int)width < 0))
431
 
    return GRUB_ERR_NONE;
432
 
  if ((y >= (int)framebuffer.render_target->viewport.height) || (y + (int)height < 0))
433
 
    return GRUB_ERR_NONE;
434
 
 
435
 
  /* Do not allow drawing out of viewport.  */
436
 
  if (x < 0)
437
 
    {
438
 
      width += x;
439
 
      x = 0;
440
 
    }
441
 
  if (y < 0)
442
 
    {
443
 
      height += y;
444
 
      y = 0;
445
 
    }
446
 
 
447
 
  if ((x + width) > framebuffer.render_target->viewport.width)
448
 
    width = framebuffer.render_target->viewport.width - x;
449
 
  if ((y + height) > framebuffer.render_target->viewport.height)
450
 
    height = framebuffer.render_target->viewport.height - y;
451
 
 
452
 
  /* Add viewport offset.  */
453
 
  x += framebuffer.render_target->viewport.x;
454
 
  y += framebuffer.render_target->viewport.y;
455
 
 
456
 
  /* Use fbblit_info to encapsulate rendering.  */
457
 
  target.mode_info = &framebuffer.render_target->mode_info;
458
 
  target.data = framebuffer.render_target->data;
459
 
 
460
 
  /* Try to figure out more optimized version.  Note that color is already
461
 
     mapped to target format so we can make assumptions based on that.  */
462
 
  if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
463
 
    {
464
 
      grub_video_fbfill_direct32 (&target, color, x, y,
465
 
                                        width, height);
466
 
      return GRUB_ERR_NONE;
467
 
    }
468
 
  else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
469
 
    {
470
 
      grub_video_fbfill_direct32 (&target, color, x, y,
471
 
                                        width, height);
472
 
      return GRUB_ERR_NONE;
473
 
    }
474
 
  else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
475
 
    {
476
 
      grub_video_fbfill_direct24 (&target, color, x, y,
477
 
                                        width, height);
478
 
      return GRUB_ERR_NONE;
479
 
    }
480
 
  else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_565)
481
 
    {
482
 
      grub_video_fbfill_direct16 (&target, color, x, y,
483
 
                                        width, height);
484
 
      return GRUB_ERR_NONE;
485
 
    }
486
 
  else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_565)
487
 
    {
488
 
      grub_video_fbfill_direct16 (&target, color, x, y,
489
 
                                        width, height);
490
 
      return GRUB_ERR_NONE;
491
 
    }
492
 
  else if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
493
 
    {
494
 
      grub_video_fbfill_direct8 (&target, color, x, y,
495
 
                                       width, height);
496
 
      return GRUB_ERR_NONE;
497
 
    }
498
 
 
499
 
  /* No optimized version found, use default (slow) filler.  */
500
 
  grub_video_fbfill (&target, color, x, y, width, height);
501
 
 
502
 
  return GRUB_ERR_NONE;
503
 
}
504
 
 
505
 
/* NOTE: This function assumes that given coordinates are within bounds of
506
 
   handled data.  */
507
 
static void
508
 
common_blitter (struct grub_video_fbblit_info *target,
509
 
                struct grub_video_fbblit_info *source,
510
 
                enum grub_video_blit_operators oper, int x, int y,
511
 
                unsigned int width, unsigned int height,
512
 
                int offset_x, int offset_y)
513
 
{
514
 
  if (oper == GRUB_VIDEO_BLIT_REPLACE)
515
 
    {
516
 
      /* Try to figure out more optimized version for replace operator.  */
517
 
      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
518
 
        {
519
 
          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
520
 
            {
521
 
              grub_video_fbblit_replace_directN (target, source,
522
 
                                                       x, y, width, height,
523
 
                                                       offset_x, offset_y);
524
 
              return;
525
 
            }
526
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
527
 
            {
528
 
              grub_video_fbblit_replace_BGRX8888_RGBX8888 (target, source,
529
 
                                                                 x, y, width, height,
530
 
                                                                 offset_x, offset_y);
531
 
              return;
532
 
            }
533
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
534
 
            {
535
 
              grub_video_fbblit_replace_BGR888_RGBX8888 (target, source,
536
 
                                                               x, y, width, height,
537
 
                                                               offset_x, offset_y);
538
 
              return;
539
 
            }
540
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
541
 
            {
542
 
              grub_video_fbblit_replace_RGB888_RGBX8888 (target, source,
543
 
                                                               x, y, width, height,
544
 
                                                               offset_x, offset_y);
545
 
              return;
546
 
            }
547
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
548
 
            {
549
 
              grub_video_fbblit_replace_index_RGBX8888 (target, source,
550
 
                                                              x, y, width, height,
551
 
                                                              offset_x, offset_y);
552
 
              return;
553
 
            }
554
 
        }
555
 
      else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
556
 
        {
557
 
          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
558
 
            {
559
 
              grub_video_fbblit_replace_BGRX8888_RGB888 (target, source,
560
 
                                                               x, y, width, height,
561
 
                                                               offset_x, offset_y);
562
 
              return;
563
 
            }
564
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
565
 
            {
566
 
              grub_video_fbblit_replace_RGBX8888_RGB888 (target, source,
567
 
                                                               x, y, width, height,
568
 
                                                               offset_x, offset_y);
569
 
              return;
570
 
            }
571
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
572
 
            {
573
 
              grub_video_fbblit_replace_BGR888_RGB888 (target, source,
574
 
                                                             x, y, width, height,
575
 
                                                             offset_x, offset_y);
576
 
              return;
577
 
            }
578
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
579
 
            {
580
 
              grub_video_fbblit_replace_directN (target, source,
581
 
                                                       x, y, width, height,
582
 
                                                       offset_x, offset_y);
583
 
              return;
584
 
            }
585
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
586
 
            {
587
 
              grub_video_fbblit_replace_index_RGB888 (target, source,
588
 
                                                            x, y, width, height,
589
 
                                                            offset_x, offset_y);
590
 
              return;
591
 
            }
592
 
        }
593
 
      else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
594
 
        {
595
 
          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
596
 
            {
597
 
              grub_video_fbblit_replace_directN (target, source,
598
 
                                                       x, y, width, height,
599
 
                                                       offset_x, offset_y);
600
 
              return;
601
 
            }
602
 
        }
603
 
      else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
604
 
        {
605
 
          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
606
 
            {
607
 
              grub_video_fbblit_replace_directN (target, source,
608
 
                                                       x, y, width, height,
609
 
                                                       offset_x, offset_y);
610
 
              return;
611
 
            }
612
 
        }
613
 
      else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
614
 
        {
615
 
          if (target->mode_info->bpp == 32)
616
 
            {
617
 
              grub_video_fbblit_replace_32bit_1bit (target, source,
618
 
                                                    x, y, width, height,
619
 
                                                    offset_x, offset_y);
620
 
              return;
621
 
            }
622
 
          else if (target->mode_info->bpp == 24)
623
 
            {
624
 
              grub_video_fbblit_replace_24bit_1bit (target, source,
625
 
                                                    x, y, width, height,
626
 
                                                    offset_x, offset_y);
627
 
              return;
628
 
            }
629
 
          else if (target->mode_info->bpp == 16)
630
 
            {
631
 
              grub_video_fbblit_replace_16bit_1bit (target, source,
632
 
                                                    x, y, width, height,
633
 
                                                    offset_x, offset_y);
634
 
              return;
635
 
            }
636
 
          else if (target->mode_info->bpp == 8)
637
 
            {
638
 
              grub_video_fbblit_replace_8bit_1bit (target, source,
639
 
                                                   x, y, width, height,
640
 
                                                   offset_x, offset_y);
641
 
              return;
642
 
            }
643
 
        }
644
 
 
645
 
      /* No optimized replace operator found, use default (slow) blitter.  */
646
 
      grub_video_fbblit_replace (target, source, x, y, width, height,
647
 
                                       offset_x, offset_y);
648
 
    }
649
 
  else
650
 
    {
651
 
      /* Try to figure out more optimized blend operator.  */
652
 
      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
653
 
        {
654
 
          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
655
 
            {
656
 
              grub_video_fbblit_blend_BGRA8888_RGBA8888 (target, source,
657
 
                                                               x, y, width, height,
658
 
                                                               offset_x, offset_y);
659
 
              return;
660
 
            }
661
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
662
 
            {
663
 
              grub_video_fbblit_blend_RGBA8888_RGBA8888 (target, source,
664
 
                                                               x, y, width, height,
665
 
                                                               offset_x, offset_y);
666
 
              return;
667
 
            }
668
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
669
 
            {
670
 
              grub_video_fbblit_blend_BGR888_RGBA8888 (target, source,
671
 
                                                             x, y, width, height,
672
 
                                                             offset_x, offset_y);
673
 
              return;
674
 
            }
675
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
676
 
            {
677
 
              grub_video_fbblit_blend_RGB888_RGBA8888 (target, source,
678
 
                                                             x, y, width, height,
679
 
                                                             offset_x, offset_y);
680
 
              return;
681
 
            }
682
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
683
 
            {
684
 
              grub_video_fbblit_blend_index_RGBA8888 (target, source,
685
 
                                                            x, y, width, height,
686
 
                                                            offset_x, offset_y);
687
 
              return;
688
 
            }
689
 
        }
690
 
      else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
691
 
        {
692
 
          /* Note: There is really no alpha information here, so blend is
693
 
             changed to replace.  */
694
 
 
695
 
          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
696
 
            {
697
 
              grub_video_fbblit_replace_BGRX8888_RGB888 (target, source,
698
 
                                                               x, y, width, height,
699
 
                                                               offset_x, offset_y);
700
 
              return;
701
 
            }
702
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
703
 
            {
704
 
              grub_video_fbblit_replace_RGBX8888_RGB888 (target, source,
705
 
                                                               x, y, width, height,
706
 
                                                               offset_x, offset_y);
707
 
              return;
708
 
            }
709
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
710
 
            {
711
 
              grub_video_fbblit_replace_BGR888_RGB888 (target, source,
712
 
                                                             x, y, width, height,
713
 
                                                             offset_x, offset_y);
714
 
              return;
715
 
            }
716
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
717
 
            {
718
 
              grub_video_fbblit_replace_directN (target, source,
719
 
                                                       x, y, width, height,
720
 
                                                       offset_x, offset_y);
721
 
              return;
722
 
            }
723
 
          else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
724
 
            {
725
 
              grub_video_fbblit_replace_index_RGB888 (target, source,
726
 
                                                            x, y, width, height,
727
 
                                                            offset_x, offset_y);
728
 
              return;
729
 
            }
730
 
        }
731
 
      else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
732
 
        {
733
 
          if (target->mode_info->blit_format
734
 
              == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888
735
 
              || target->mode_info->blit_format
736
 
              == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
737
 
            {
738
 
              grub_video_fbblit_blend_XXXA8888_1bit (target, source,
739
 
                                                     x, y, width, height,
740
 
                                                     offset_x, offset_y);
741
 
              return;
742
 
            }
743
 
          else if (target->mode_info->blit_format
744
 
                   == GRUB_VIDEO_BLIT_FORMAT_BGR_888
745
 
                   || target->mode_info->blit_format
746
 
                   == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
747
 
            {
748
 
              grub_video_fbblit_blend_XXX888_1bit (target, source,
749
 
                                                   x, y, width, height,
750
 
                                                   offset_x, offset_y);
751
 
              return;
752
 
            }
753
 
          else if (target->mode_info->blit_format
754
 
                   == GRUB_VIDEO_BLIT_FORMAT_BGR_565
755
 
                   || target->mode_info->blit_format
756
 
                   == GRUB_VIDEO_BLIT_FORMAT_RGB_565)
757
 
            {
758
 
              grub_video_fbblit_blend_XXX565_1bit (target, source,
759
 
                                                   x, y, width, height,
760
 
                                                   offset_x, offset_y);
761
 
              return;
762
 
            }
763
 
 
764
 
        }
765
 
 
766
 
 
767
 
      /* No optimized blend operation found, use default (slow) blitter.  */
768
 
      grub_video_fbblit_blend (target, source, x, y, width, height,
769
 
                                     offset_x, offset_y);
770
 
    }
771
 
}
772
 
 
773
 
grub_err_t
774
 
grub_video_fb_blit_bitmap (struct grub_video_bitmap *bitmap,
775
 
                           enum grub_video_blit_operators oper, int x, int y,
776
 
                           int offset_x, int offset_y,
777
 
                           unsigned int width, unsigned int height)
778
 
{
779
 
  struct grub_video_fbblit_info source;
780
 
  struct grub_video_fbblit_info target;
781
 
 
782
 
  /* Make sure there is something to do.  */
783
 
  if ((width == 0) || (height == 0))
784
 
    return GRUB_ERR_NONE;
785
 
  if ((x >= (int)framebuffer.render_target->viewport.width) || (x + (int)width < 0))
786
 
    return GRUB_ERR_NONE;
787
 
  if ((y >= (int)framebuffer.render_target->viewport.height) || (y + (int)height < 0))
788
 
    return GRUB_ERR_NONE;
789
 
  if ((x + (int)bitmap->mode_info.width) < 0)
790
 
    return GRUB_ERR_NONE;
791
 
  if ((y + (int)bitmap->mode_info.height) < 0)
792
 
    return GRUB_ERR_NONE;
793
 
  if ((offset_x >= (int)bitmap->mode_info.width)
794
 
      || (offset_x + (int)width < 0))
795
 
    return GRUB_ERR_NONE;
796
 
  if ((offset_y >= (int)bitmap->mode_info.height)
797
 
      || (offset_y + (int)height < 0))
798
 
    return GRUB_ERR_NONE;
799
 
 
800
 
  /* If we have negative coordinates, optimize drawing to minimum.  */
801
 
  if (offset_x < 0)
802
 
    {
803
 
      width += offset_x;
804
 
      x -= offset_x;
805
 
      offset_x = 0;
806
 
    }
807
 
 
808
 
  if (offset_y < 0)
809
 
    {
810
 
      height += offset_y;
811
 
      y -= offset_y;
812
 
      offset_y = 0;
813
 
    }
814
 
 
815
 
  if (x < 0)
816
 
    {
817
 
      width += x;
818
 
      offset_x -= x;
819
 
      x = 0;
820
 
    }
821
 
 
822
 
  if (y < 0)
823
 
    {
824
 
      height += y;
825
 
      offset_y -= y;
826
 
      y = 0;
827
 
    }
828
 
 
829
 
  /* Do not allow drawing out of viewport.  */
830
 
  if ((x + width) > framebuffer.render_target->viewport.width)
831
 
    width = framebuffer.render_target->viewport.width - x;
832
 
  if ((y + height) > framebuffer.render_target->viewport.height)
833
 
    height = framebuffer.render_target->viewport.height - y;
834
 
 
835
 
  if ((offset_x + width) > bitmap->mode_info.width)
836
 
    width = bitmap->mode_info.width - offset_x;
837
 
  if ((offset_y + height) > bitmap->mode_info.height)
838
 
    height = bitmap->mode_info.height - offset_y;
839
 
 
840
 
  /* Limit drawing to source render target dimensions.  */
841
 
  if (width > bitmap->mode_info.width)
842
 
    width = bitmap->mode_info.width;
843
 
 
844
 
  if (height > bitmap->mode_info.height)
845
 
    height = bitmap->mode_info.height;
846
 
 
847
 
  /* Add viewport offset.  */
848
 
  x += framebuffer.render_target->viewport.x;
849
 
  y += framebuffer.render_target->viewport.y;
850
 
 
851
 
  /* Use fbblit_info to encapsulate rendering.  */
852
 
  source.mode_info = &bitmap->mode_info;
853
 
  source.data = bitmap->data;
854
 
  target.mode_info = &framebuffer.render_target->mode_info;
855
 
  target.data = framebuffer.render_target->data;
856
 
 
857
 
  /* Do actual blitting.  */
858
 
  common_blitter (&target, &source, oper, x, y, width, height,
859
 
                  offset_x, offset_y);
860
 
 
861
 
  return GRUB_ERR_NONE;
862
 
}
863
 
 
864
 
grub_err_t
865
 
grub_video_fb_blit_render_target (struct grub_video_fbrender_target *source,
866
 
                                   enum grub_video_blit_operators oper,
867
 
                                   int x, int y, int offset_x, int offset_y,
868
 
                                   unsigned int width, unsigned int height)
869
 
{
870
 
  struct grub_video_fbblit_info source_info;
871
 
  struct grub_video_fbblit_info target_info;
872
 
 
873
 
  /* Make sure there is something to do.  */
874
 
  if ((width == 0) || (height == 0))
875
 
    return GRUB_ERR_NONE;
876
 
  if ((x >= (int)framebuffer.render_target->viewport.width) || (x + (int)width < 0))
877
 
    return GRUB_ERR_NONE;
878
 
  if ((y >= (int)framebuffer.render_target->viewport.height) || (y + (int)height < 0))
879
 
    return GRUB_ERR_NONE;
880
 
  if ((x + (int)source->mode_info.width) < 0)
881
 
    return GRUB_ERR_NONE;
882
 
  if ((y + (int)source->mode_info.height) < 0)
883
 
    return GRUB_ERR_NONE;
884
 
  if ((offset_x >= (int)source->mode_info.width)
885
 
      || (offset_x + (int)width < 0))
886
 
    return GRUB_ERR_NONE;
887
 
  if ((offset_y >= (int)source->mode_info.height)
888
 
      || (offset_y + (int)height < 0))
889
 
    return GRUB_ERR_NONE;
890
 
 
891
 
  /* If we have negative coordinates, optimize drawing to minimum.  */
892
 
  if (offset_x < 0)
893
 
    {
894
 
      width += offset_x;
895
 
      x -= offset_x;
896
 
      offset_x = 0;
897
 
    }
898
 
 
899
 
  if (offset_y < 0)
900
 
    {
901
 
      height += offset_y;
902
 
      y -= offset_y;
903
 
      offset_y = 0;
904
 
    }
905
 
 
906
 
  if (x < 0)
907
 
    {
908
 
      width += x;
909
 
      offset_x -= x;
910
 
      x = 0;
911
 
    }
912
 
 
913
 
  if (y < 0)
914
 
    {
915
 
      height += y;
916
 
      offset_y -= y;
917
 
      y = 0;
918
 
    }
919
 
 
920
 
  /* Do not allow drawing out of viewport.  */
921
 
  if ((x + width) > framebuffer.render_target->viewport.width)
922
 
    width = framebuffer.render_target->viewport.width - x;
923
 
  if ((y + height) > framebuffer.render_target->viewport.height)
924
 
    height = framebuffer.render_target->viewport.height - y;
925
 
 
926
 
  if ((offset_x + width) > source->mode_info.width)
927
 
    width = source->mode_info.width - offset_x;
928
 
  if ((offset_y + height) > source->mode_info.height)
929
 
    height = source->mode_info.height - offset_y;
930
 
 
931
 
  /* Limit drawing to source render target dimensions.  */
932
 
  if (width > source->mode_info.width)
933
 
    width = source->mode_info.width;
934
 
 
935
 
  if (height > source->mode_info.height)
936
 
    height = source->mode_info.height;
937
 
 
938
 
  /* Add viewport offset.  */
939
 
  x += framebuffer.render_target->viewport.x;
940
 
  y += framebuffer.render_target->viewport.y;
941
 
 
942
 
  /* Use fbblit_info to encapsulate rendering.  */
943
 
  source_info.mode_info = &source->mode_info;
944
 
  source_info.data = source->data;
945
 
  target_info.mode_info = &framebuffer.render_target->mode_info;
946
 
  target_info.data = framebuffer.render_target->data;
947
 
 
948
 
  /* Do actual blitting.  */
949
 
  common_blitter (&target_info, &source_info, oper, x, y, width, height,
950
 
                  offset_x, offset_y);
951
 
 
952
 
  return GRUB_ERR_NONE;
953
 
}
954
 
 
955
 
grub_err_t
956
 
grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
957
 
{
958
 
  int width;
959
 
  int height;
960
 
  int src_x;
961
 
  int src_y;
962
 
  int dst_x;
963
 
  int dst_y;
964
 
 
965
 
  /* 1. Check if we have something to do.  */
966
 
  if ((dx == 0) && (dy == 0))
967
 
    return GRUB_ERR_NONE;
968
 
 
969
 
  width = framebuffer.render_target->viewport.width - grub_abs (dx);
970
 
  height = framebuffer.render_target->viewport.height - grub_abs (dy);
971
 
 
972
 
  if (dx < 0)
973
 
    {
974
 
      src_x = framebuffer.render_target->viewport.x - dx;
975
 
      dst_x = framebuffer.render_target->viewport.x;
976
 
    }
977
 
  else
978
 
    {
979
 
      src_x = framebuffer.render_target->viewport.x;
980
 
      dst_x = framebuffer.render_target->viewport.x + dx;
981
 
    }
982
 
 
983
 
  if (dy < 0)
984
 
    {
985
 
      src_y = framebuffer.render_target->viewport.y - dy;
986
 
      dst_y = framebuffer.render_target->viewport.y;
987
 
    }
988
 
  else
989
 
    {
990
 
      src_y = framebuffer.render_target->viewport.y;
991
 
      dst_y = framebuffer.render_target->viewport.y + dy;
992
 
    }
993
 
 
994
 
  /* 2. Check if there is need to copy data.  */
995
 
  if ((grub_abs (dx) < framebuffer.render_target->viewport.width)
996
 
       && (grub_abs (dy) < framebuffer.render_target->viewport.height))
997
 
    {
998
 
      /* 3. Move data in render target.  */
999
 
      struct grub_video_fbblit_info target;
1000
 
      int i, j;
1001
 
      int linedelta, linelen;
1002
 
 
1003
 
      target.mode_info = &framebuffer.render_target->mode_info;
1004
 
      target.data = framebuffer.render_target->data;
1005
 
 
1006
 
      linedelta = target.mode_info->pitch
1007
 
        - width * target.mode_info->bytes_per_pixel;
1008
 
      linelen = width * target.mode_info->bytes_per_pixel;
1009
 
#define DO_SCROLL                                                    \
1010
 
      /* Check vertical direction of the move.  */                   \
1011
 
      if (dy < 0 || (dy == 0 && dx < 0))                             \
1012
 
        {                                                            \
1013
 
          dst = (void *) grub_video_fb_get_video_ptr (&target,       \
1014
 
                                                      dst_x, dst_y); \
1015
 
          src = (void *) grub_video_fb_get_video_ptr (&target,       \
1016
 
                                                      src_x, src_y); \
1017
 
          /* 3a. Move data upwards.  */                              \
1018
 
          for (j = 0; j < height; j++)                               \
1019
 
            {                                                        \
1020
 
              for (i = 0; i < linelen; i++)                          \
1021
 
                *(dst++) = *(src++);                                 \
1022
 
              dst += linedelta;                                      \
1023
 
              src += linedelta;                                      \
1024
 
            }                                                        \
1025
 
        }                                                            \
1026
 
      else                                                           \
1027
 
        {                                                            \
1028
 
          /* 3b. Move data downwards.  */                            \
1029
 
          dst = (void *) grub_video_fb_get_video_ptr (&target,       \
1030
 
                                                      dst_x + width, \
1031
 
                                             dst_y + height - 1);    \
1032
 
          src = (void *) grub_video_fb_get_video_ptr (&target,       \
1033
 
                                                      src_x + width, \
1034
 
                                             src_y + height - 1);    \
1035
 
          dst--;                                                     \
1036
 
          src--;                                                     \
1037
 
          for (j = 0; j < height; j++)                               \
1038
 
            {                                                        \
1039
 
              for (i = 0; i < linelen; i++)                          \
1040
 
                *(dst--) = *(src--);                                 \
1041
 
              dst -= linedelta;                                      \
1042
 
              src -= linedelta;                                      \
1043
 
            }                                                        \
1044
 
        }
1045
 
 
1046
 
      /* If everything is aligned on 32-bit use 32-bit copy.  */
1047
 
      if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y)
1048
 
          % sizeof (grub_uint32_t) == 0
1049
 
          && (grub_addr_t) grub_video_fb_get_video_ptr (&target, dst_x, dst_y) 
1050
 
          % sizeof (grub_uint32_t) == 0
1051
 
          && linelen % sizeof (grub_uint32_t) == 0
1052
 
          && linedelta % sizeof (grub_uint32_t) == 0)
1053
 
        {
1054
 
          grub_uint32_t *src, *dst;
1055
 
          linelen /= sizeof (grub_uint32_t);
1056
 
          linedelta /= sizeof (grub_uint32_t);
1057
 
          DO_SCROLL
1058
 
        }
1059
 
      /* If everything is aligned on 16-bit use 16-bit copy.  */
1060
 
      else if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y)
1061
 
               % sizeof (grub_uint16_t) == 0
1062
 
               && (grub_addr_t) grub_video_fb_get_video_ptr (&target,
1063
 
                                                             dst_x, dst_y) 
1064
 
               % sizeof (grub_uint16_t) == 0
1065
 
               && linelen % sizeof (grub_uint16_t) == 0
1066
 
               && linedelta % sizeof (grub_uint16_t) == 0)
1067
 
        {
1068
 
          grub_uint16_t *src, *dst;
1069
 
          linelen /= sizeof (grub_uint16_t);
1070
 
          linedelta /= sizeof (grub_uint16_t);
1071
 
          DO_SCROLL
1072
 
        }
1073
 
      /* If not aligned at all use 8-bit copy.  */
1074
 
      else
1075
 
        {
1076
 
          grub_uint8_t *src, *dst;
1077
 
          DO_SCROLL
1078
 
        }       
1079
 
    }
1080
 
 
1081
 
  /* 4. Fill empty space with specified color.  In this implementation
1082
 
     there might be colliding areas but at the moment there is no need
1083
 
     to optimize this.  */
1084
 
 
1085
 
  /* 4a. Fill top & bottom parts.  */
1086
 
  if (dy > 0)
1087
 
    grub_video_fb_fill_rect (color, 0, 0, framebuffer.render_target->viewport.width, dy);
1088
 
  else if (dy < 0)
1089
 
    {
1090
 
      if (framebuffer.render_target->viewport.height < grub_abs (dy))
1091
 
        dy = -framebuffer.render_target->viewport.height;
1092
 
 
1093
 
      grub_video_fb_fill_rect (color, 0, framebuffer.render_target->viewport.height + dy,
1094
 
                                framebuffer.render_target->viewport.width, -dy);
1095
 
    }
1096
 
 
1097
 
  /* 4b. Fill left & right parts.  */
1098
 
  if (dx > 0)
1099
 
    grub_video_fb_fill_rect (color, 0, 0,
1100
 
                              dx, framebuffer.render_target->viewport.height);
1101
 
  else if (dx < 0)
1102
 
    {
1103
 
      if (framebuffer.render_target->viewport.width < grub_abs (dx))
1104
 
        dx = -framebuffer.render_target->viewport.width;
1105
 
 
1106
 
      grub_video_fb_fill_rect (color, framebuffer.render_target->viewport.width + dx, 0,
1107
 
                                -dx, framebuffer.render_target->viewport.height);
1108
 
    }
1109
 
 
1110
 
  return GRUB_ERR_NONE;
1111
 
}
1112
 
 
1113
 
 
1114
 
grub_err_t
1115
 
grub_video_fb_create_render_target (struct grub_video_fbrender_target **result,
1116
 
                                    unsigned int width, unsigned int height,
1117
 
                                    unsigned int mode_type __attribute__ ((unused)))
1118
 
{
1119
 
  struct grub_video_fbrender_target *target;
1120
 
  unsigned int size;
1121
 
 
1122
 
  /* Validate arguments.  */
1123
 
  if ((! result)
1124
 
      || (width == 0)
1125
 
      || (height == 0))
1126
 
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
1127
 
                       "invalid argument given");
1128
 
 
1129
 
  /* Allocate memory for render target.  */
1130
 
  target = grub_malloc (sizeof (struct grub_video_fbrender_target));
1131
 
  if (! target)
1132
 
    return grub_errno;
1133
 
 
1134
 
  /* TODO: Implement other types too.
1135
 
     Currently only 32bit render targets are supported.  */
1136
 
 
1137
 
  /* Mark render target as allocated.  */
1138
 
  target->is_allocated = 1;
1139
 
 
1140
 
  /* Maximize viewport.  */
1141
 
  target->viewport.x = 0;
1142
 
  target->viewport.y = 0;
1143
 
  target->viewport.width = width;
1144
 
  target->viewport.height = height;
1145
 
 
1146
 
  /* Setup render target format.  */
1147
 
  target->mode_info.width = width;
1148
 
  target->mode_info.height = height;
1149
 
  target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB
1150
 
                                | GRUB_VIDEO_MODE_TYPE_ALPHA;
1151
 
  target->mode_info.bpp = 32;
1152
 
  target->mode_info.bytes_per_pixel = 4;
1153
 
  target->mode_info.pitch = target->mode_info.bytes_per_pixel * width;
1154
 
  target->mode_info.number_of_colors = framebuffer.palette_size; /* Emulated palette.  */
1155
 
  target->mode_info.red_mask_size = 8;
1156
 
  target->mode_info.red_field_pos = 0;
1157
 
  target->mode_info.green_mask_size = 8;
1158
 
  target->mode_info.green_field_pos = 8;
1159
 
  target->mode_info.blue_mask_size = 8;
1160
 
  target->mode_info.blue_field_pos = 16;
1161
 
  target->mode_info.reserved_mask_size = 8;
1162
 
  target->mode_info.reserved_field_pos = 24;
1163
 
 
1164
 
  target->mode_info.blit_format = grub_video_get_blit_format (&target->mode_info);
1165
 
 
1166
 
  /* Calculate size needed for the data.  */
1167
 
  size = (width * target->mode_info.bytes_per_pixel) * height;
1168
 
 
1169
 
  target->data = grub_malloc (size);
1170
 
  if (! target->data)
1171
 
    {
1172
 
      grub_free (target);
1173
 
      return grub_errno;
1174
 
    }
1175
 
 
1176
 
  /* Clear render target with black and maximum transparency.  */
1177
 
  grub_memset (target->data, 0, size);
1178
 
 
1179
 
  /* TODO: Add render target to render target list.  */
1180
 
 
1181
 
  /* Save result to caller.  */
1182
 
  *result = target;
1183
 
 
1184
 
  return GRUB_ERR_NONE;
1185
 
}
1186
 
 
1187
 
grub_err_t
1188
 
grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_target **result,
1189
 
                                                 const struct grub_video_mode_info *mode_info,
1190
 
                                                 void *ptr)
1191
 
{
1192
 
  struct grub_video_fbrender_target *target;
1193
 
  unsigned y;
1194
 
 
1195
 
  /* Allocate memory for render target.  */
1196
 
  target = grub_malloc (sizeof (struct grub_video_fbrender_target));
1197
 
  if (! target)
1198
 
    return grub_errno;
1199
 
 
1200
 
  /* Mark framebuffer memory as non allocated.  */
1201
 
  target->is_allocated = 0;
1202
 
  target->data = ptr;
1203
 
 
1204
 
  grub_memcpy (&(target->mode_info), mode_info, sizeof (target->mode_info));
1205
 
 
1206
 
  /* Reset viewport to match new mode.  */
1207
 
  target->viewport.x = 0;
1208
 
  target->viewport.y = 0;
1209
 
  target->viewport.width = mode_info->width;
1210
 
  target->viewport.height = mode_info->height;
1211
 
 
1212
 
  /* Clear render target with black and maximum transparency.  */
1213
 
  for (y = 0; y < mode_info->height; y++)
1214
 
    grub_memset (target->data + mode_info->pitch * y, 0,
1215
 
                 mode_info->bytes_per_pixel * mode_info->width);
1216
 
 
1217
 
  /* Save result to caller.  */
1218
 
  *result = target;
1219
 
 
1220
 
  return GRUB_ERR_NONE;
1221
 
}
1222
 
 
1223
 
grub_err_t
1224
 
grub_video_fb_delete_render_target (struct grub_video_fbrender_target *target)
1225
 
{
1226
 
  /* If there is no target, then just return without error.  */
1227
 
  if (! target)
1228
 
    return GRUB_ERR_NONE;
1229
 
 
1230
 
  /* TODO: Delist render target from render target list.  */
1231
 
 
1232
 
  /* If this is software render target, free it's memory.  */
1233
 
  if (target->is_allocated)
1234
 
    grub_free (target->data);
1235
 
 
1236
 
  /* Free render target.  */
1237
 
  grub_free (target);
1238
 
 
1239
 
  return GRUB_ERR_NONE;
1240
 
}
1241
 
 
1242
 
grub_err_t
1243
 
grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target)
1244
 
{
1245
 
  if (target == (struct grub_video_fbrender_target *)
1246
 
      GRUB_VIDEO_RENDER_TARGET_DISPLAY)
1247
 
    target = framebuffer.back_target;
1248
 
 
1249
 
  if (! target->data)
1250
 
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
1251
 
                       "invalid render target given");
1252
 
 
1253
 
  framebuffer.render_target = target;
1254
 
 
1255
 
  return GRUB_ERR_NONE;
1256
 
}
1257
 
 
1258
 
grub_err_t
1259
 
grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **target)
1260
 
{
1261
 
  *target = framebuffer.render_target;
1262
 
 
1263
 
  if (*target == framebuffer.back_target)
1264
 
    *target = (struct grub_video_fbrender_target *) GRUB_VIDEO_RENDER_TARGET_DISPLAY;
1265
 
 
1266
 
  return GRUB_ERR_NONE;
1267
 
}
1268
 
 
1269
 
static grub_err_t
1270
 
doublebuf_blit_update_screen (struct grub_video_fbrender_target *front,
1271
 
                              struct grub_video_fbrender_target *back)
1272
 
{
1273
 
  grub_memcpy (front->data, back->data,
1274
 
               front->mode_info.pitch * front->mode_info.height);
1275
 
  return GRUB_ERR_NONE;
1276
 
}
1277
 
 
1278
 
static grub_err_t
1279
 
grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front,
1280
 
                                   struct grub_video_fbrender_target **back,
1281
 
                                   struct grub_video_mode_info mode_info,
1282
 
                                   void *framebuf)
1283
 
{
1284
 
  grub_err_t err;
1285
 
  int page_size = mode_info.pitch * mode_info.height;
1286
 
 
1287
 
  err = grub_video_fb_create_render_target_from_pointer (front, &mode_info,
1288
 
                                                         framebuf);
1289
 
  if (err)
1290
 
    return err;
1291
 
 
1292
 
  framebuffer.offscreen_buffer = grub_malloc (page_size);
1293
 
  if (! framebuffer.offscreen_buffer)
1294
 
    {
1295
 
      grub_video_fb_delete_render_target (*front);
1296
 
      *front = 0;
1297
 
      return grub_errno;
1298
 
    }
1299
 
 
1300
 
  err = grub_video_fb_create_render_target_from_pointer (back, &mode_info,
1301
 
                                                         framebuffer.offscreen_buffer);
1302
 
 
1303
 
  if (err)
1304
 
    {
1305
 
      grub_video_fb_delete_render_target (*front);
1306
 
      grub_free (framebuffer.offscreen_buffer);
1307
 
      framebuffer.offscreen_buffer = 0;
1308
 
      *front = 0;
1309
 
      return grub_errno;
1310
 
    }
1311
 
  (*back)->is_allocated = 1;
1312
 
 
1313
 
  framebuffer.update_screen = doublebuf_blit_update_screen;
1314
 
 
1315
 
  return GRUB_ERR_NONE;
1316
 
}
1317
 
 
1318
 
static grub_err_t
1319
 
doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front
1320
 
                                      __attribute__ ((unused)),
1321
 
                                      struct grub_video_fbrender_target *back
1322
 
                                      __attribute__ ((unused)))
1323
 
{
1324
 
  int new_displayed_page;
1325
 
  struct grub_video_fbrender_target *target;
1326
 
  grub_err_t err;
1327
 
 
1328
 
  /* Swap the page numbers in the framebuffer struct.  */
1329
 
  new_displayed_page = framebuffer.render_page;
1330
 
  framebuffer.render_page = framebuffer.displayed_page;
1331
 
  framebuffer.displayed_page = new_displayed_page;
1332
 
 
1333
 
  err = framebuffer.set_page (framebuffer.displayed_page);
1334
 
  if (err)
1335
 
    {
1336
 
      /* Restore previous state.  */
1337
 
      framebuffer.render_page = framebuffer.displayed_page;
1338
 
      framebuffer.displayed_page = new_displayed_page;
1339
 
      return err;
1340
 
    }
1341
 
 
1342
 
  target = framebuffer.back_target;
1343
 
  framebuffer.back_target = framebuffer.front_target;
1344
 
  framebuffer.front_target = target;
1345
 
 
1346
 
  if (framebuffer.front_target->mode_info.mode_type
1347
 
      & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)
1348
 
    grub_memcpy (framebuffer.back_target->data, framebuffer.front_target->data,
1349
 
                 framebuffer.back_target->mode_info.pitch
1350
 
                 * framebuffer.back_target->mode_info.height);
1351
 
 
1352
 
  err = grub_video_fb_get_active_render_target (&target);
1353
 
  if (err)
1354
 
    return err;
1355
 
 
1356
 
  if (framebuffer.render_target == framebuffer.back_target)
1357
 
    framebuffer.render_target = framebuffer.front_target;
1358
 
  else if (framebuffer.render_target == framebuffer.front_target)
1359
 
    framebuffer.render_target = framebuffer.back_target;
1360
 
 
1361
 
  return err;
1362
 
}
1363
 
 
1364
 
static grub_err_t
1365
 
doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info,
1366
 
                             volatile void *page0_ptr,
1367
 
                             grub_video_fb_set_page_t set_page_in,
1368
 
                             volatile void *page1_ptr)
1369
 
{
1370
 
  grub_err_t err;
1371
 
 
1372
 
  framebuffer.displayed_page = 0;
1373
 
  framebuffer.render_page = 1;
1374
 
 
1375
 
  framebuffer.update_screen = doublebuf_pageflipping_update_screen;
1376
 
 
1377
 
  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target,
1378
 
                                                         mode_info,
1379
 
                                                         (void *) page0_ptr);
1380
 
  if (err)
1381
 
    return err;
1382
 
 
1383
 
  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
1384
 
                                                         mode_info,
1385
 
                                                         (void *) page1_ptr);
1386
 
  if (err)
1387
 
    {
1388
 
      grub_video_fb_delete_render_target (framebuffer.front_target);
1389
 
      return err;
1390
 
    }
1391
 
 
1392
 
  /* Set the framebuffer memory data pointer and display the right page.  */
1393
 
  err = set_page_in (framebuffer.displayed_page);
1394
 
  if (err)
1395
 
    {
1396
 
      grub_video_fb_delete_render_target (framebuffer.front_target);
1397
 
      grub_video_fb_delete_render_target (framebuffer.back_target);
1398
 
      return err;
1399
 
    }
1400
 
  framebuffer.set_page = set_page_in;
1401
 
 
1402
 
  return GRUB_ERR_NONE;
1403
 
}
1404
 
 
1405
 
/* Select the best double buffering mode available.  */
1406
 
grub_err_t
1407
 
grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
1408
 
                     struct grub_video_mode_info *mode_info,
1409
 
                     volatile void *page0_ptr,
1410
 
                     grub_video_fb_set_page_t set_page_in,
1411
 
                     volatile void *page1_ptr)
1412
 
{
1413
 
  grub_err_t err;
1414
 
  int updating_swap_needed;
1415
 
 
1416
 
  updating_swap_needed
1417
 
    = grub_video_check_mode_flag (mode_type, mode_mask,
1418
 
                                  GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP, 0);
1419
 
 
1420
 
  /* Do double buffering only if it's either requested or efficient.  */
1421
 
  if (set_page_in && grub_video_check_mode_flag (mode_type, mode_mask,
1422
 
                                                 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
1423
 
                                                 !updating_swap_needed))
1424
 
    {
1425
 
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
1426
 
      if (updating_swap_needed)
1427
 
        mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP;
1428
 
 
1429
 
      err = doublebuf_pageflipping_init (mode_info, page0_ptr,
1430
 
                                         set_page_in,
1431
 
                                         page1_ptr);
1432
 
      if (!err)
1433
 
        {
1434
 
          framebuffer.render_target = framebuffer.back_target;
1435
 
          return GRUB_ERR_NONE;
1436
 
        }
1437
 
      
1438
 
      mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1439
 
                                | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
1440
 
 
1441
 
      grub_errno = GRUB_ERR_NONE;
1442
 
    }
1443
 
 
1444
 
  if (grub_video_check_mode_flag (mode_type, mode_mask,
1445
 
                                  GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
1446
 
                                  0))
1447
 
    {
1448
 
      mode_info->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1449
 
                               | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
1450
 
 
1451
 
      err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target,
1452
 
                                               &framebuffer.back_target,
1453
 
                                               *mode_info,
1454
 
                                               (void *) page0_ptr);
1455
 
 
1456
 
      if (!err)
1457
 
        {
1458
 
          framebuffer.render_target = framebuffer.back_target;
1459
 
          return GRUB_ERR_NONE;
1460
 
        }
1461
 
 
1462
 
      mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
1463
 
                                | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
1464
 
 
1465
 
      grub_errno = GRUB_ERR_NONE;
1466
 
    }
1467
 
 
1468
 
  /* Fall back to no double buffering.  */
1469
 
  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target,
1470
 
                                                         mode_info,
1471
 
                                                         (void *) page0_ptr);
1472
 
 
1473
 
  if (err)
1474
 
    return err;
1475
 
 
1476
 
  framebuffer.back_target = framebuffer.front_target;
1477
 
  framebuffer.update_screen = 0;
1478
 
 
1479
 
  mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
1480
 
 
1481
 
  framebuffer.render_target = framebuffer.back_target;
1482
 
 
1483
 
  return GRUB_ERR_NONE;
1484
 
}
1485
 
 
1486
 
 
1487
 
grub_err_t
1488
 
grub_video_fb_swap_buffers (void)
1489
 
{
1490
 
  grub_err_t err;
1491
 
  if (!framebuffer.update_screen)
1492
 
    return GRUB_ERR_NONE;
1493
 
 
1494
 
  err = framebuffer.update_screen (framebuffer.front_target,
1495
 
                                   framebuffer.back_target);
1496
 
  if (err)
1497
 
    return err;
1498
 
 
1499
 
  return GRUB_ERR_NONE;
1500
 
}
1501
 
 
1502
 
grub_err_t
1503
 
grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info,
1504
 
                                 void **framebuf)
1505
 
{
1506
 
  grub_memcpy (mode_info, &(framebuffer.front_target->mode_info),
1507
 
               sizeof (*mode_info));
1508
 
  *framebuf = framebuffer.front_target->data;
1509
 
 
1510
 
  grub_video_fb_fini ();
1511
 
 
1512
 
  return GRUB_ERR_NONE;
1513
 
}