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