update .gitignore
[pcsx_rearmed.git] / frontend / libretro.c
1 /*
2  * (C) notaz, 2012
3  *
4  * This work is licensed under the terms of the GNU GPLv2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "../libpcsxcore/misc.h"
13 #include "../libpcsxcore/psxcounters.h"
14 #include "../libpcsxcore/psxmem_map.h"
15 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
16 #include "../plugins/dfsound/out.h"
17 #include "../plugins/gpulib/cspace.h"
18 #include "main.h"
19 #include "plugin.h"
20 #include "plugin_lib.h"
21 #include "revision.h"
22 #include "libretro.h"
23
24 static retro_video_refresh_t video_cb;
25 static retro_input_poll_t input_poll_cb;
26 static retro_input_state_t input_state_cb;
27 static retro_environment_t environ_cb;
28 static retro_audio_sample_batch_t audio_batch_cb;
29
30 static void *vout_buf;
31 static int samples_sent, samples_to_send;
32 static int plugins_opened;
33
34 /* memory card data */
35 extern char Mcd1Data[MCD_SIZE];
36 extern char McdDisable[2];
37
38 /* PCSX ReARMed core calls and stuff */
39 int in_type1, in_type2;
40 int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
41 int in_keystate;
42 int in_enable_vibration;
43
44 static void init_memcard(char *mcd_data)
45 {
46         unsigned off = 0;
47         unsigned i;
48
49         memset(mcd_data, 0, MCD_SIZE);
50
51         mcd_data[off++] = 'M';
52         mcd_data[off++] = 'C';
53         off += 0x7d;
54         mcd_data[off++] = 0x0e;
55
56         for (i = 0; i < 15; i++) {
57                 mcd_data[off++] = 0xa0;
58                 off += 0x07;
59                 mcd_data[off++] = 0xff;
60                 mcd_data[off++] = 0xff;
61                 off += 0x75;
62                 mcd_data[off++] = 0xa0;
63         }
64
65         for (i = 0; i < 20; i++) {
66                 mcd_data[off++] = 0xff;
67                 mcd_data[off++] = 0xff;
68                 mcd_data[off++] = 0xff;
69                 mcd_data[off++] = 0xff;
70                 off += 0x04;
71                 mcd_data[off++] = 0xff;
72                 mcd_data[off++] = 0xff;
73                 off += 0x76;
74         }
75 }
76
77 static int vout_open(void)
78 {
79         return 0;
80 }
81
82 static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp)
83 {
84 }
85
86 #ifdef FRONTEND_SUPPORTS_RGB565
87 static void convert(void *buf, size_t bytes)
88 {
89         unsigned int i, v, *p = buf;
90
91         for (i = 0; i < bytes / 4; i++) {
92                 v = p[i];
93                 p[i] = (v & 0x001f001f) | ((v >> 1) & 0x7fe07fe0);
94         }
95 }
96 #endif
97
98 static unsigned game_width;
99 static unsigned game_height;
100
101 static void vout_flip(const void *vram, int stride, int bgr24, int w, int h)
102 {
103         unsigned short *dest = vout_buf;
104         const unsigned short *src = vram;
105         int dstride = w, h1 = h;
106
107         if (vram == NULL) {
108                 // blanking
109                 memset(vout_buf, 0, dstride * h * 2);
110                 goto out;
111         }
112
113         if (bgr24)
114         {
115                 // XXX: could we switch to RETRO_PIXEL_FORMAT_XRGB8888 here?
116                 for (; h1-- > 0; dest += dstride, src += stride)
117                 {
118                         bgr888_to_rgb565(dest, src, w * 3);
119                 }
120         }
121         else
122         {
123                 for (; h1-- > 0; dest += dstride, src += stride)
124                 {
125                         bgr555_to_rgb565(dest, src, w * 2);
126                 }
127         }
128
129 out:
130 #ifndef FRONTEND_SUPPORTS_RGB565
131    convert(vout_buf, w * h * 2);
132 #endif
133    game_width = w;
134    game_height = h;
135         pl_rearmed_cbs.flip_cnt++;
136 }
137
138 static void vout_close(void)
139 {
140 }
141
142 static void *pl_mmap(unsigned int size)
143 {
144         return psxMap(0, size, 0, MAP_TAG_VRAM);
145 }
146
147 static void pl_munmap(void *ptr, unsigned int size)
148 {
149         psxUnmap(ptr, size, MAP_TAG_VRAM);
150 }
151
152 struct rearmed_cbs pl_rearmed_cbs = {
153         .pl_vout_open = vout_open,
154         .pl_vout_set_mode = vout_set_mode,
155         .pl_vout_flip = vout_flip,
156         .pl_vout_close = vout_close,
157         .mmap = pl_mmap,
158         .munmap = pl_munmap,
159         /* from psxcounters */
160         .gpu_hcnt = &hSyncCount,
161         .gpu_frame_count = &frame_counter,
162 };
163
164 void pl_frame_limit(void)
165 {
166         /* called once per frame, make psxCpu->Execute() above return */
167         stop = 1;
168 }
169
170 void pl_timing_prepare(int is_pal)
171 {
172 }
173
174 void plat_trigger_vibrate(int is_strong)
175 {
176 }
177
178 void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in)
179 {
180 }
181
182 /* sound calls */
183 static int snd_init(void)
184 {
185         return 0;
186 }
187
188 static void snd_finish(void)
189 {
190 }
191
192 static int snd_busy(void)
193 {
194         if (samples_to_send > samples_sent)
195                 return 0; /* give more samples */
196         else
197                 return 1;
198 }
199
200 static void snd_feed(void *buf, int bytes)
201 {
202         audio_batch_cb(buf, bytes / 4);
203         samples_sent += bytes / 4;
204 }
205
206 void out_register_libretro(struct out_driver *drv)
207 {
208         drv->name = "libretro";
209         drv->init = snd_init;
210         drv->finish = snd_finish;
211         drv->busy = snd_busy;
212         drv->feed = snd_feed;
213 }
214
215 /* libretro */
216 void retro_set_environment(retro_environment_t cb) { environ_cb = cb; }
217 void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
218 void retro_set_audio_sample(retro_audio_sample_t cb) { (void)cb; }
219 void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
220 void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
221 void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
222
223 unsigned retro_api_version(void)
224 {
225         return RETRO_API_VERSION;
226 }
227
228 void retro_set_controller_port_device(unsigned port, unsigned device)
229 {
230 }
231
232 void retro_get_system_info(struct retro_system_info *info)
233 {
234         memset(info, 0, sizeof(*info));
235         info->library_name = "PCSX-ReARMed";
236         info->library_version = REV;
237         info->valid_extensions = "bin|cue|img|mdf|pbp|cbn";
238         info->need_fullpath = true;
239 }
240
241 void retro_get_system_av_info(struct retro_system_av_info *info)
242 {
243         memset(info, 0, sizeof(*info));
244         info->timing.fps            = 60;
245         info->timing.sample_rate    = 44100;
246         info->geometry.base_width   = 320;
247         info->geometry.base_height  = 240;
248         info->geometry.max_width    = 640;
249         info->geometry.max_height   = 512;
250         info->geometry.aspect_ratio = 4.0 / 3.0;
251 }
252
253 /* TODO */
254 size_t retro_serialize_size(void) 
255
256         return 0;
257 }
258
259 bool retro_serialize(void *data, size_t size)
260
261         return false;
262 }
263
264 bool retro_unserialize(const void *data, size_t size)
265 {
266         return false;
267 }
268
269 void retro_cheat_reset(void)
270 {
271 }
272
273 void retro_cheat_set(unsigned index, bool enabled, const char *code)
274 {
275 }
276
277 bool retro_load_game(const struct retro_game_info *info)
278 {
279 #ifdef FRONTEND_SUPPORTS_RGB565
280         enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
281         if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
282                 fprintf(stderr, "RGB565 supported, using it\n");
283         }
284 #endif
285
286         if (plugins_opened) {
287                 ClosePlugins();
288                 plugins_opened = 0;
289         }
290
291         set_cd_image(info->path);
292
293         /* have to reload after set_cd_image for correct cdr plugin */
294         if (LoadPlugins() == -1) {
295                 printf("faled to load plugins\n");
296                 return false;
297         }
298
299         plugins_opened = 1;
300         NetOpened = 0;
301
302         if (OpenPlugins() == -1) {
303                 printf("faled to open plugins\n");
304                 return false;
305         }
306
307         plugin_call_rearmed_cbs();
308
309         Config.PsxAuto = 1;
310         if (CheckCdrom() == -1) {
311                 printf("unsupported/invalid CD image: %s\n", info->path);
312                 return false;
313         }
314
315         SysReset();
316
317         if (LoadCdrom() == -1) {
318                 printf("could not load CD-ROM!\n");
319                 return false;
320         }
321         emu_on_new_cd(0);
322
323         return true;
324 }
325
326 bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
327 {
328         return false;
329 }
330
331 void retro_unload_game(void) 
332 {
333 }
334
335 unsigned retro_get_region(void)
336 {
337         return RETRO_REGION_NTSC;
338 }
339
340 void *retro_get_memory_data(unsigned id)
341 {
342         return Mcd1Data;
343 }
344
345 size_t retro_get_memory_size(unsigned id)
346 {
347         return MCD_SIZE;
348 }
349
350 void retro_reset(void)
351 {
352         SysReset();
353 }
354
355 static const unsigned short retro_psx_map[] = {
356         [RETRO_DEVICE_ID_JOYPAD_B]      = 1 << DKEY_CROSS,
357         [RETRO_DEVICE_ID_JOYPAD_Y]      = 1 << DKEY_SQUARE,
358         [RETRO_DEVICE_ID_JOYPAD_SELECT] = 1 << DKEY_SELECT,
359         [RETRO_DEVICE_ID_JOYPAD_START]  = 1 << DKEY_START,
360         [RETRO_DEVICE_ID_JOYPAD_UP]     = 1 << DKEY_UP,
361         [RETRO_DEVICE_ID_JOYPAD_DOWN]   = 1 << DKEY_DOWN,
362         [RETRO_DEVICE_ID_JOYPAD_LEFT]   = 1 << DKEY_LEFT,
363         [RETRO_DEVICE_ID_JOYPAD_RIGHT]  = 1 << DKEY_RIGHT,
364         [RETRO_DEVICE_ID_JOYPAD_A]      = 1 << DKEY_CIRCLE,
365         [RETRO_DEVICE_ID_JOYPAD_X]      = 1 << DKEY_TRIANGLE,
366         [RETRO_DEVICE_ID_JOYPAD_L]      = 1 << DKEY_L1,
367         [RETRO_DEVICE_ID_JOYPAD_R]      = 1 << DKEY_R1,
368         [RETRO_DEVICE_ID_JOYPAD_L2]     = 1 << DKEY_L2,
369         [RETRO_DEVICE_ID_JOYPAD_R2]     = 1 << DKEY_R2,
370         [RETRO_DEVICE_ID_JOYPAD_L3]     = 1 << DKEY_L3,
371         [RETRO_DEVICE_ID_JOYPAD_R3]     = 1 << DKEY_R3,
372 };
373 #define RETRO_PSX_MAP_LEN (sizeof(retro_psx_map) / sizeof(retro_psx_map[0]))
374
375 void retro_run(void) 
376 {
377         int i;
378
379         input_poll_cb();
380         in_keystate = 0;
381         for (i = 0; i < RETRO_PSX_MAP_LEN; i++)
382                 if (input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, i))
383                         in_keystate |= retro_psx_map[i];
384         in_keystate <<= 16;
385         for (i = 0; i < RETRO_PSX_MAP_LEN; i++)
386                 if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i))
387                         in_keystate |= retro_psx_map[i];
388
389         stop = 0;
390         psxCpu->Execute();
391
392         samples_to_send += 44100 / 60;
393         video_cb(vout_buf, game_width, game_height, game_width * 2);
394 }
395
396 void retro_init(void)
397 {
398         const char *bios[] = { "scph1001", "scph5501", "scph7001" };
399         const char *dir;
400         char path[256];
401         FILE *f = NULL;
402         int i, ret, level;
403
404         ret = emu_core_preinit();
405         ret |= emu_core_init();
406         if (ret != 0) {
407                 printf("PCSX init failed, sorry\n");
408                 exit(1);
409         }
410
411         vout_buf = malloc(640 * 512 * 2);
412
413         if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
414         {
415                 snprintf(Config.BiosDir, sizeof(Config.BiosDir), "%s/", dir);
416
417                 for (i = 0; i < sizeof(bios) / sizeof(bios[0]); i++) {
418                         snprintf(path, sizeof(path), "%s/%s.bin", dir, bios[i]);
419                         f = fopen(path, "r");
420                         if (f != NULL) {
421                                 snprintf(Config.Bios, sizeof(Config.Bios), "%s.bin", bios[i]);
422                                 break;
423                         }
424                 }
425         }
426         if (f != NULL) {
427                 printf("found BIOS file: %s\n", Config.Bios);
428                 fclose(f);
429         }
430         else
431                 printf("no BIOS files found.\n");
432
433         level = 1;
434         environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
435
436         McdDisable[0] = 0;
437         McdDisable[1] = 1;
438         init_memcard(Mcd1Data);
439 }
440
441 void retro_deinit(void)
442 {
443         SysClose();
444         free(vout_buf);
445         vout_buf = NULL;
446 }