sdl.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. #define grub_video_render_target grub_video_fbrender_target
  19. #include <config-util.h>
  20. #include <config.h>
  21. #include <grub/err.h>
  22. #include <grub/types.h>
  23. #include <grub/dl.h>
  24. #include <grub/misc.h>
  25. #include <grub/mm.h>
  26. #include <grub/video.h>
  27. #include <grub/video_fb.h>
  28. #ifdef HAVE_SDL2
  29. #include <SDL2/SDL.h>
  30. #else
  31. #include <SDL/SDL.h>
  32. #endif
  33. GRUB_MOD_LICENSE ("GPLv3+");
  34. #ifdef HAVE_SDL2
  35. static SDL_Window *window = NULL;
  36. static SDL_Texture *texture = NULL;
  37. static SDL_Renderer *renderer = NULL;
  38. #else
  39. static SDL_Surface *window = NULL;
  40. #endif
  41. static SDL_Surface *surface = NULL;
  42. static struct grub_video_render_target *sdl_render_target;
  43. static struct grub_video_mode_info mode_info;
  44. static grub_err_t
  45. grub_video_sdl_set_palette (unsigned int start, unsigned int count,
  46. struct grub_video_palette_data *palette_data);
  47. static grub_err_t
  48. grub_video_sdl_init (void)
  49. {
  50. window = NULL;
  51. if (SDL_Init (SDL_INIT_VIDEO) < 0)
  52. return grub_error (GRUB_ERR_BAD_DEVICE, "could not init SDL: %s",
  53. SDL_GetError ());
  54. grub_memset (&mode_info, 0, sizeof (mode_info));
  55. return grub_video_fb_init ();
  56. }
  57. static grub_err_t
  58. grub_video_sdl_fini (void)
  59. {
  60. SDL_Quit ();
  61. window = NULL;
  62. grub_memset (&mode_info, 0, sizeof (mode_info));
  63. return grub_video_fb_fini ();
  64. }
  65. static inline unsigned int
  66. get_mask_size (grub_uint32_t mask)
  67. {
  68. unsigned i;
  69. for (i = 0; mask > 1U << i; i++);
  70. return i;
  71. }
  72. static grub_err_t
  73. grub_video_sdl_setup (unsigned int width, unsigned int height,
  74. unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused)))
  75. {
  76. int depth;
  77. int flags = 0;
  78. grub_err_t err;
  79. /* Decode depth from mode_type. If it is zero, then autodetect. */
  80. depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
  81. >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
  82. if (depth == 0)
  83. depth = 32;
  84. if (width == 0 && height == 0)
  85. {
  86. width = 800;
  87. height = 600;
  88. }
  89. #ifdef HAVE_SDL2
  90. window = SDL_CreateWindow ("grub-emu",
  91. SDL_WINDOWPOS_UNDEFINED,
  92. SDL_WINDOWPOS_UNDEFINED,
  93. width, height, flags);
  94. if(window == NULL)
  95. return grub_error (GRUB_ERR_BAD_DEVICE, "could not open window: %s",
  96. SDL_GetError ());
  97. renderer = SDL_CreateRenderer (window, -1, 0);
  98. if (renderer == NULL)
  99. return grub_error (GRUB_ERR_BAD_DEVICE, "could not open renderer: %s",
  100. SDL_GetError ());
  101. texture = SDL_CreateTexture (renderer,
  102. SDL_PIXELFORMAT_ARGB8888,
  103. SDL_TEXTUREACCESS_STREAMING,
  104. width, height);
  105. if (texture == NULL)
  106. return grub_error (GRUB_ERR_BAD_DEVICE, "could not create texture: %s",
  107. SDL_GetError ());
  108. /*
  109. * An empty surface that acts as the pixel buffer, the texture will receive the pixels
  110. * from here.
  111. */
  112. surface = SDL_CreateRGBSurface (0, width, height, depth, 0, 0, 0, 0);
  113. if (surface == NULL)
  114. return grub_error (GRUB_ERR_BAD_DEVICE, "could not open surface: %s",
  115. SDL_GetError ());
  116. #else
  117. if ((mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)
  118. || !(mode_mask & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED))
  119. flags |= SDL_DOUBLEBUF;
  120. window = SDL_SetVideoMode (width, height, depth, flags | SDL_HWSURFACE);
  121. if (window == NULL)
  122. window = SDL_SetVideoMode (width, height, depth, flags | SDL_SWSURFACE);
  123. if (window == NULL)
  124. return grub_error (GRUB_ERR_BAD_DEVICE, "could not open window: %s",
  125. SDL_GetError ());
  126. surface = window;
  127. #endif
  128. grub_memset (&sdl_render_target, 0, sizeof (sdl_render_target));
  129. mode_info.mode_type = 0;
  130. mode_info.width = surface->w;
  131. mode_info.height = surface->h;
  132. #ifndef HAVE_SDL2
  133. if (surface->flags & SDL_DOUBLEBUF)
  134. mode_info.mode_type
  135. |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
  136. #endif
  137. if (surface->format->palette)
  138. mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
  139. else
  140. mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_RGB;
  141. mode_info.bpp = surface->format->BitsPerPixel;
  142. mode_info.bytes_per_pixel = surface->format->BytesPerPixel;
  143. mode_info.pitch = surface->pitch;
  144. /* In index color mode, number of colors. In RGB mode this is 256. */
  145. if (surface->format->palette)
  146. mode_info.number_of_colors
  147. = 1 << surface->format->BitsPerPixel;
  148. else
  149. mode_info.number_of_colors = 256;
  150. if (! surface->format->palette)
  151. {
  152. mode_info.red_mask_size
  153. = get_mask_size (surface->format->Rmask >> surface->format->Rshift);
  154. mode_info.red_field_pos = surface->format->Rshift;
  155. mode_info.green_mask_size
  156. = get_mask_size (surface->format->Gmask >> surface->format->Gshift);
  157. mode_info.green_field_pos = surface->format->Gshift;
  158. mode_info.blue_mask_size
  159. = get_mask_size (surface->format->Bmask >> surface->format->Bshift);
  160. mode_info.blue_field_pos = surface->format->Bshift;
  161. mode_info.reserved_mask_size
  162. = get_mask_size (surface->format->Amask >> surface->format->Ashift);
  163. mode_info.reserved_field_pos = surface->format->Ashift;
  164. mode_info.blit_format
  165. = grub_video_get_blit_format (&mode_info);
  166. }
  167. err = grub_video_fb_create_render_target_from_pointer (&sdl_render_target,
  168. &mode_info,
  169. surface->pixels);
  170. if (err)
  171. return err;
  172. /* Copy default palette to initialize emulated palette. */
  173. grub_video_sdl_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
  174. grub_video_fbstd_colors);
  175. /* Reset render target to SDL one. */
  176. return grub_video_fb_set_active_render_target (sdl_render_target);
  177. }
  178. static grub_err_t
  179. grub_video_sdl_set_palette (unsigned int start, unsigned int count,
  180. struct grub_video_palette_data *palette_data)
  181. {
  182. unsigned i;
  183. if (surface->format->palette)
  184. {
  185. SDL_Color *tmp;
  186. if (start >= mode_info.number_of_colors)
  187. return GRUB_ERR_NONE;
  188. if (start + count > mode_info.number_of_colors)
  189. count = mode_info.number_of_colors - start;
  190. tmp = grub_calloc (count, sizeof (tmp[0]));
  191. for (i = 0; i < count; i++)
  192. {
  193. tmp[i].r = palette_data[i].r;
  194. tmp[i].g = palette_data[i].g;
  195. tmp[i].b = palette_data[i].b;
  196. #ifdef HAVE_SDL2
  197. tmp[i].a = palette_data[i].a;
  198. #else
  199. tmp[i].unused = palette_data[i].a;
  200. #endif
  201. }
  202. #ifdef HAVE_SDL2
  203. SDL_SetPaletteColors (surface->format->palette, tmp, 0 /* firstcolor */, count);
  204. #else
  205. SDL_SetColors (window, tmp, start, count);
  206. #endif
  207. grub_free (tmp);
  208. }
  209. return grub_video_fb_set_palette (start, count, palette_data);
  210. }
  211. static grub_err_t
  212. grub_video_sdl_swap_buffers (void)
  213. {
  214. #ifdef HAVE_SDL2
  215. if (SDL_UpdateTexture (texture, NULL, surface->pixels, surface->w * sizeof (Uint32)) < 0)
  216. return grub_error (GRUB_ERR_BAD_DEVICE, "could not update texture: %s",
  217. SDL_GetError ());
  218. if (SDL_RenderClear (renderer) < 0)
  219. return grub_error (GRUB_ERR_BAD_DEVICE, "could not clear renderer: %s",
  220. SDL_GetError ());
  221. if (SDL_RenderCopy (renderer, texture, NULL, NULL) < 0)
  222. return grub_error (GRUB_ERR_BAD_DEVICE, "could not copy texture to renderer: %s",
  223. SDL_GetError ());
  224. SDL_RenderPresent (renderer);
  225. #else
  226. if (SDL_Flip (window) < 0)
  227. return grub_error (GRUB_ERR_BAD_DEVICE, "could not swap buffers: %s",
  228. SDL_GetError ());
  229. #endif
  230. return GRUB_ERR_NONE;
  231. }
  232. static grub_err_t
  233. grub_video_sdl_set_active_render_target (struct grub_video_render_target *target)
  234. {
  235. if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
  236. return grub_video_fb_set_active_render_target (sdl_render_target);
  237. return grub_video_fb_set_active_render_target (target);
  238. }
  239. static struct grub_video_adapter grub_video_sdl_adapter =
  240. {
  241. .name = "SDL Video Driver",
  242. .id = GRUB_VIDEO_DRIVER_SDL,
  243. .prio = GRUB_VIDEO_ADAPTER_PRIO_FIRMWARE,
  244. .init = grub_video_sdl_init,
  245. .fini = grub_video_sdl_fini,
  246. .setup = grub_video_sdl_setup,
  247. .get_info = grub_video_fb_get_info,
  248. .set_palette = grub_video_sdl_set_palette,
  249. .get_palette = grub_video_fb_get_palette,
  250. .set_viewport = grub_video_fb_set_viewport,
  251. .get_viewport = grub_video_fb_get_viewport,
  252. .set_region = grub_video_fb_set_region,
  253. .get_region = grub_video_fb_get_region,
  254. .set_area_status = grub_video_fb_set_area_status,
  255. .get_area_status = grub_video_fb_get_area_status,
  256. .map_color = grub_video_fb_map_color,
  257. .map_rgb = grub_video_fb_map_rgb,
  258. .map_rgba = grub_video_fb_map_rgba,
  259. .unmap_color = grub_video_fb_unmap_color,
  260. .fill_rect = grub_video_fb_fill_rect,
  261. .blit_bitmap = grub_video_fb_blit_bitmap,
  262. .blit_render_target = grub_video_fb_blit_render_target,
  263. .scroll = grub_video_fb_scroll,
  264. .swap_buffers = grub_video_sdl_swap_buffers,
  265. .create_render_target = grub_video_fb_create_render_target,
  266. .delete_render_target = grub_video_fb_delete_render_target,
  267. .set_active_render_target = grub_video_sdl_set_active_render_target,
  268. .get_active_render_target = grub_video_fb_get_active_render_target,
  269. .next = 0
  270. };
  271. GRUB_MOD_INIT(sdl)
  272. {
  273. grub_video_register (&grub_video_sdl_adapter);
  274. }
  275. GRUB_MOD_FINI(sdl)
  276. {
  277. grub_video_unregister (&grub_video_sdl_adapter);
  278. }