plat_sdl.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * PicoDrive
  3. * (C) notaz, 2013
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #include <stdio.h>
  9. #include "../libpicofe/input.h"
  10. #include "../libpicofe/plat.h"
  11. #include "../libpicofe/plat_sdl.h"
  12. #include "../libpicofe/in_sdl.h"
  13. #include "../libpicofe/gl.h"
  14. #include "emu.h"
  15. #include "menu_pico.h"
  16. #include "input_pico.h"
  17. #include "plat_sdl.h"
  18. #include "version.h"
  19. #include <pico/pico.h>
  20. static void *shadow_fb;
  21. static struct in_pdata in_sdl_platform_data = {
  22. .defbinds = in_sdl_defbinds,
  23. .key_map = in_sdl_key_map,
  24. .joy_map = in_sdl_joy_map,
  25. };
  26. /* YUV stuff */
  27. static int yuv_ry[32], yuv_gy[32], yuv_by[32];
  28. static unsigned char yuv_u[32 * 2], yuv_v[32 * 2];
  29. static unsigned char yuv_y[256];
  30. static struct uyvy { uint32_t y:8; uint32_t vyu:24; } yuv_uyvy[65536];
  31. void bgr_to_uyvy_init(void)
  32. {
  33. int i, v;
  34. /* init yuv converter:
  35. y0 = (int)((0.299f * r0) + (0.587f * g0) + (0.114f * b0));
  36. y1 = (int)((0.299f * r1) + (0.587f * g1) + (0.114f * b1));
  37. u = (int)(8 * 0.565f * (b0 - y0)) + 128;
  38. v = (int)(8 * 0.713f * (r0 - y0)) + 128;
  39. */
  40. for (i = 0; i < 32; i++) {
  41. yuv_ry[i] = (int)(0.299f * i * 65536.0f + 0.5f);
  42. yuv_gy[i] = (int)(0.587f * i * 65536.0f + 0.5f);
  43. yuv_by[i] = (int)(0.114f * i * 65536.0f + 0.5f);
  44. }
  45. for (i = -32; i < 32; i++) {
  46. v = (int)(8 * 0.565f * i) + 128;
  47. if (v < 0)
  48. v = 0;
  49. if (v > 255)
  50. v = 255;
  51. yuv_u[i + 32] = v;
  52. v = (int)(8 * 0.713f * i) + 128;
  53. if (v < 0)
  54. v = 0;
  55. if (v > 255)
  56. v = 255;
  57. yuv_v[i + 32] = v;
  58. }
  59. // valid Y range seems to be 16..235
  60. for (i = 0; i < 256; i++) {
  61. yuv_y[i] = 16 + 219 * i / 32;
  62. }
  63. // everything combined into one large array for speed
  64. for (i = 0; i < 65536; i++) {
  65. int r = (i >> 11) & 0x1f, g = (i >> 6) & 0x1f, b = (i >> 0) & 0x1f;
  66. int y = (yuv_ry[r] + yuv_gy[g] + yuv_by[b]) >> 16;
  67. yuv_uyvy[i].y = yuv_y[y];
  68. yuv_uyvy[i].vyu = (yuv_v[r-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[b-y + 32];
  69. }
  70. }
  71. void rgb565_to_uyvy(void *d, const void *s, int pixels, int x2)
  72. {
  73. uint32_t *dst = d;
  74. const uint16_t *src = s;
  75. if (x2)
  76. for (; pixels > 0; src += 4, dst += 4, pixels -= 4)
  77. {
  78. struct uyvy *uyvy0 = yuv_uyvy + src[0], *uyvy1 = yuv_uyvy + src[1];
  79. struct uyvy *uyvy2 = yuv_uyvy + src[2], *uyvy3 = yuv_uyvy + src[3];
  80. dst[0] = (uyvy0->y << 24) | uyvy0->vyu;
  81. dst[1] = (uyvy1->y << 24) | uyvy1->vyu;
  82. dst[2] = (uyvy2->y << 24) | uyvy2->vyu;
  83. dst[3] = (uyvy3->y << 24) | uyvy3->vyu;
  84. } else
  85. for (; pixels > 0; src += 4, dst += 2, pixels -= 4)
  86. {
  87. struct uyvy *uyvy0 = yuv_uyvy + src[0], *uyvy1 = yuv_uyvy + src[1];
  88. struct uyvy *uyvy2 = yuv_uyvy + src[2], *uyvy3 = yuv_uyvy + src[3];
  89. dst[0] = (uyvy1->y << 24) | uyvy0->vyu;
  90. dst[1] = (uyvy3->y << 24) | uyvy2->vyu;
  91. }
  92. }
  93. static int clear_buf_cnt, clear_stat_cnt;
  94. void plat_video_flip(void)
  95. {
  96. if (plat_sdl_overlay != NULL) {
  97. SDL_Rect dstrect =
  98. { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
  99. SDL_LockYUVOverlay(plat_sdl_overlay);
  100. rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb,
  101. g_screen_ppitch * g_screen_height,
  102. plat_sdl_overlay->w > 2*plat_sdl_overlay->h);
  103. SDL_UnlockYUVOverlay(plat_sdl_overlay);
  104. SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
  105. }
  106. else if (plat_sdl_gl_active) {
  107. gl_flip(shadow_fb, g_screen_ppitch, g_screen_height);
  108. }
  109. else {
  110. if (SDL_MUSTLOCK(plat_sdl_screen)) {
  111. SDL_UnlockSurface(plat_sdl_screen);
  112. SDL_Flip(plat_sdl_screen);
  113. SDL_LockSurface(plat_sdl_screen);
  114. } else
  115. SDL_Flip(plat_sdl_screen);
  116. g_screen_ptr = plat_sdl_screen->pixels;
  117. plat_video_set_buffer(g_screen_ptr);
  118. if (clear_buf_cnt) {
  119. memset(g_screen_ptr, 0, plat_sdl_screen->w*plat_sdl_screen->h * 2);
  120. clear_buf_cnt--;
  121. }
  122. }
  123. if (clear_stat_cnt) {
  124. unsigned short *d = (unsigned short *)g_screen_ptr + g_screen_ppitch * g_screen_height;
  125. int l = g_screen_ppitch * 8;
  126. memset((int *)(d - l), 0, l * 2);
  127. clear_stat_cnt--;
  128. }
  129. }
  130. void plat_video_wait_vsync(void)
  131. {
  132. }
  133. void plat_video_clear_status(void)
  134. {
  135. clear_stat_cnt = 3; // do it thrice in case of triple buffering
  136. }
  137. void plat_video_clear_buffers(void)
  138. {
  139. if (plat_sdl_overlay != NULL || plat_sdl_gl_active)
  140. memset(shadow_fb, 0, plat_sdl_screen->w*plat_sdl_screen->h * 2);
  141. else {
  142. memset(g_screen_ptr, 0, plat_sdl_screen->w*plat_sdl_screen->h * 2);
  143. clear_buf_cnt = 3; // do it thrice in case of triple buffering
  144. }
  145. }
  146. void plat_video_menu_enter(int is_rom_loaded)
  147. {
  148. if (SDL_MUSTLOCK(plat_sdl_screen))
  149. SDL_UnlockSurface(plat_sdl_screen);
  150. plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 1);
  151. g_screen_ptr = shadow_fb;
  152. plat_video_set_buffer(g_screen_ptr);
  153. }
  154. void plat_video_menu_begin(void)
  155. {
  156. if (plat_sdl_overlay != NULL || plat_sdl_gl_active) {
  157. g_menuscreen_ptr = shadow_fb;
  158. }
  159. else {
  160. if (SDL_MUSTLOCK(plat_sdl_screen))
  161. SDL_LockSurface(plat_sdl_screen);
  162. g_menuscreen_ptr = plat_sdl_screen->pixels;
  163. }
  164. }
  165. void plat_video_menu_end(void)
  166. {
  167. if (plat_sdl_overlay != NULL) {
  168. SDL_Rect dstrect =
  169. { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
  170. SDL_LockYUVOverlay(plat_sdl_overlay);
  171. rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb,
  172. g_menuscreen_pp * g_menuscreen_h, 0);
  173. SDL_UnlockYUVOverlay(plat_sdl_overlay);
  174. SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
  175. }
  176. else if (plat_sdl_gl_active) {
  177. gl_flip(g_menuscreen_ptr, g_menuscreen_pp, g_menuscreen_h);
  178. }
  179. else {
  180. if (SDL_MUSTLOCK(plat_sdl_screen))
  181. SDL_UnlockSurface(plat_sdl_screen);
  182. SDL_Flip(plat_sdl_screen);
  183. }
  184. g_menuscreen_ptr = NULL;
  185. }
  186. void plat_video_menu_leave(void)
  187. {
  188. }
  189. void plat_video_loop_prepare(void)
  190. {
  191. if (plat_sdl_overlay != NULL || plat_sdl_gl_active) {
  192. g_screen_width = 320;
  193. g_screen_height = 240;
  194. g_screen_ppitch = g_screen_width;
  195. plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0);
  196. g_screen_ptr = shadow_fb;
  197. }
  198. else {
  199. g_screen_width = g_menuscreen_w;
  200. g_screen_height = g_menuscreen_h;
  201. g_screen_ppitch = g_menuscreen_pp;
  202. plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0);
  203. if (SDL_MUSTLOCK(plat_sdl_screen))
  204. SDL_LockSurface(plat_sdl_screen);
  205. g_screen_ptr = plat_sdl_screen->pixels;
  206. }
  207. plat_video_set_buffer(g_screen_ptr);
  208. }
  209. void plat_early_init(void)
  210. {
  211. }
  212. static void plat_sdl_quit(void)
  213. {
  214. // for now..
  215. exit(1);
  216. }
  217. void plat_init(void)
  218. {
  219. int shadow_size;
  220. int ret;
  221. ret = plat_sdl_init();
  222. if (ret != 0)
  223. exit(1);
  224. SDL_ShowCursor(0);
  225. #if defined(__RG350__) || defined(__GCW0__) || defined(__OPENDINGUX__)
  226. // opendingux on JZ47x0 may falsely report a HW overlay, fix to window
  227. plat_target.vout_method = 0;
  228. #endif
  229. plat_sdl_quit_cb = plat_sdl_quit;
  230. SDL_WM_SetCaption("PicoDrive " VERSION, NULL);
  231. g_menuscreen_w = plat_sdl_screen->w;
  232. g_menuscreen_h = plat_sdl_screen->h;
  233. g_menuscreen_pp = g_menuscreen_w;
  234. g_menuscreen_ptr = NULL;
  235. shadow_size = g_menuscreen_w * g_menuscreen_h * 2;
  236. if (shadow_size < 320 * 480 * 2)
  237. shadow_size = 320 * 480 * 2;
  238. shadow_fb = calloc(1, shadow_size);
  239. g_menubg_ptr = calloc(1, shadow_size);
  240. if (shadow_fb == NULL || g_menubg_ptr == NULL) {
  241. fprintf(stderr, "OOM\n");
  242. exit(1);
  243. }
  244. g_screen_width = 320;
  245. g_screen_height = 240;
  246. g_screen_ppitch = 320;
  247. g_screen_ptr = shadow_fb;
  248. in_sdl_platform_data.kmap_size = in_sdl_key_map_sz,
  249. in_sdl_platform_data.jmap_size = in_sdl_joy_map_sz,
  250. in_sdl_platform_data.key_names = *in_sdl_key_names,
  251. in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler);
  252. in_probe();
  253. bgr_to_uyvy_init();
  254. }
  255. void plat_finish(void)
  256. {
  257. free(shadow_fb);
  258. shadow_fb = NULL;
  259. free(g_menubg_ptr);
  260. g_menubg_ptr = NULL;
  261. plat_sdl_finish();
  262. }