integrate M-HT's neon scalers
[gpsp.git] / pandora / pnd.c
1 /* gameplaySP - pandora backend
2  *
3  * Copyright (C) 2011 notaz <notasas@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program 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 GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 #include "../common.h"
21 #include <X11/keysym.h>
22 #include "linux/omapfb.h" //
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <sys/ioctl.h>
27
28 #include "../arm/neon_scale2x.h"
29 #include "../arm/neon_scale3x.h"
30 #include "../arm/neon_eagle2x.h"
31 #include "linux/fbdev.h"
32 #include "linux/xenv.h"
33
34 enum gpsp_key {
35   GKEY_UP       = 1 << 0,
36   GKEY_LEFT     = 1 << 1,
37   GKEY_DOWN     = 1 << 2,
38   GKEY_RIGHT    = 1 << 3,
39   GKEY_START    = 1 << 4,
40   GKEY_SELECT   = 1 << 5,
41   GKEY_L        = 1 << 6,
42   GKEY_R        = 1 << 7,
43   GKEY_A        = 1 << 8,
44   GKEY_B        = 1 << 9,
45   GKEY_X        = 1 << 10,
46   GKEY_Y        = 1 << 11,
47   GKEY_1        = 1 << 12,
48   GKEY_2        = 1 << 13,
49   GKEY_3        = 1 << 14,
50   GKEY_4        = 1 << 15,
51   GKEY_MENU     = 1 << 16,
52 };
53
54 u32 button_plat_mask_to_config[PLAT_BUTTON_COUNT] =
55 {
56   GKEY_UP,
57   GKEY_LEFT,
58   GKEY_DOWN,
59   GKEY_RIGHT,
60   GKEY_START,
61   GKEY_SELECT,
62   GKEY_L,
63   GKEY_R,
64   GKEY_A,
65   GKEY_B,
66   GKEY_X,
67   GKEY_Y,
68   GKEY_1,
69   GKEY_2,
70   GKEY_3,
71   GKEY_4,
72   GKEY_MENU,
73 };
74
75 u32 gamepad_config_map[PLAT_BUTTON_COUNT] =
76 {
77   BUTTON_ID_UP,                 // Up
78   BUTTON_ID_LEFT,               // Left
79   BUTTON_ID_DOWN,               // Down
80   BUTTON_ID_RIGHT,              // Right
81   BUTTON_ID_START,              // Start
82   BUTTON_ID_SELECT,             // Select
83   BUTTON_ID_L,                  // Ltrigger
84   BUTTON_ID_R,                  // Rtrigger
85   BUTTON_ID_FPS,                // A
86   BUTTON_ID_A,                  // B
87   BUTTON_ID_B,                  // X
88   BUTTON_ID_MENU,               // Y
89   BUTTON_ID_SAVESTATE,          // 1
90   BUTTON_ID_LOADSTATE,          // 2
91   BUTTON_ID_FASTFORWARD,        // 3
92   BUTTON_ID_NONE,               // 4
93   BUTTON_ID_MENU                // Space
94 };
95
96 static const u32 xk_to_gkey[] = {
97   XK_Up, XK_Left, XK_Down, XK_Right, XK_Alt_L, XK_Control_L,
98   XK_Shift_R, XK_Control_R, XK_Home, XK_End, XK_Page_Down, XK_Page_Up,
99   XK_1, XK_2, XK_3, XK_4, XK_space,
100 };
101
102 static const u8 gkey_to_cursor[32] = {
103   [0 ... 31] = CURSOR_NONE,
104   [0] = CURSOR_UP, CURSOR_LEFT, CURSOR_DOWN, CURSOR_RIGHT, CURSOR_NONE, CURSOR_NONE,
105   CURSOR_L, CURSOR_R, CURSOR_SELECT, CURSOR_SELECT, CURSOR_EXIT, CURSOR_BACK,
106 };
107
108 struct vout_fbdev *fb;
109 static void *fb_current;
110 static int bounce_buf[400 * 272 * 2 / 4];
111 static int src_w = 240, src_h = 160;
112 static enum software_filter {
113   SWFILTER_NONE = 0,
114   SWFILTER_SCALE2X,
115   SWFILTER_SCALE3X,
116   SWFILTER_EAGLE2X,
117 } sw_filter;
118
119 // (240*3 * 160*3 * 2 * 3)
120 #define MAX_VRAM_SIZE (400*2 * 272*2 * 2 * 3)
121
122
123 static int omap_setup_layer(int fd, int enabled, int x, int y, int w, int h)
124 {
125   struct omapfb_plane_info pi = { 0, };
126   struct omapfb_mem_info mi = { 0, };
127   int ret;
128
129   ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
130   if (ret != 0) {
131     perror("QUERY_PLANE");
132     return -1;
133   }
134
135   ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
136   if (ret != 0) {
137     perror("QUERY_MEM");
138     return -1;
139   }
140
141   /* must disable when changing stuff */
142   if (pi.enabled) {
143     pi.enabled = 0;
144     ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
145     if (ret != 0)
146       perror("SETUP_PLANE");
147   }
148
149   /* alloc enough for 3x scaled tripple buffering */
150   if (mi.size < MAX_VRAM_SIZE) {
151     mi.size = MAX_VRAM_SIZE;
152     ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
153     if (ret != 0) {
154       perror("SETUP_MEM");
155       return -1;
156     }
157   }
158
159   pi.pos_x = x;
160   pi.pos_y = y;
161   pi.out_width = w;
162   pi.out_height = h;
163   pi.enabled = enabled;
164
165   ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
166   if (ret != 0) {
167     perror("SETUP_PLANE");
168     return -1;
169   }
170
171   return 0;
172 }
173
174 void gpsp_plat_init(void)
175 {
176   int ret, w, h, fd;
177   const char *layer_fb_name;
178
179   ret = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
180   if (ret != 0) {
181     fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
182     exit(1);
183   }
184
185   layer_fb_name = getenv("FBDEV_LAYER");
186   if (layer_fb_name == NULL)
187     layer_fb_name = "/dev/fb1";
188
189   ret = xenv_init();
190   if (ret != 0) {
191     fprintf(stderr, "xenv_init failed with %d\n", ret);
192     exit(1);
193   }
194
195   // must set the layer up first to be able to use it
196   fd = open(layer_fb_name, O_RDWR);
197   if (fd == -1) {
198     fprintf(stderr, "%s: ", layer_fb_name);
199     perror("open");
200     exit(1);
201   }
202
203   ret = omap_setup_layer(fd, 0, 0, 0, 400, 272);
204   close(fd);
205   if (ret != 0) {
206     fprintf(stderr, "failed to set up layer, exiting.\n");
207     exit(1);
208   }
209
210   // double of original menu size
211   w = 400*2;
212   h = 272*2;
213   fb = vout_fbdev_init("/dev/fb1", &w, &h, 16, 3);
214   if (fb == NULL) {
215     fprintf(stderr, "vout_fbdev_init failed\n");
216     exit(1);
217   }
218
219   // default to 3x scale
220   screen_scale = 2;
221 }
222
223 void gpsp_plat_quit(void)
224 {
225   xenv_finish();
226   omap_setup_layer(vout_fbdev_get_fd(fb), 0, 0, 0, 0, 0);
227   vout_fbdev_finish(fb);
228   SDL_Quit();
229 }
230
231 u32 gpsp_plat_joystick_read(void)
232 {
233   static int gkeystate;
234   int key, is_down, i;
235   int gkey = -1;
236   
237   key = xenv_update(&is_down);
238   for (i = 0; i < sizeof(xk_to_gkey) / sizeof(xk_to_gkey[0]); i++) {
239     if (key == xk_to_gkey[i]) {
240       gkey = i;
241       break;
242     }
243   }
244
245   if (gkey >= 0) {
246     if (is_down)
247       gkeystate |= 1 << gkey;
248     else
249       gkeystate &= ~(1 << gkey);
250   }
251   
252   return gkeystate;
253 }
254
255 u32 gpsp_plat_buttons_to_cursor(u32 buttons)
256 {
257   int i;
258
259   if (buttons == 0)
260     return CURSOR_NONE;
261
262   for (i = 0; (buttons & 1) == 0; i++, buttons >>= 1)
263     ;
264
265   return gkey_to_cursor[i];
266 }
267
268 static void set_filter(int is_filtered)
269 {
270   static int was_filtered = -1;
271   char buf[128];
272
273   if (is_filtered == was_filtered)
274     return;
275
276   snprintf(buf, sizeof(buf), "sudo -n /usr/pandora/scripts/op_videofir.sh %s",
277     is_filtered ? "default" : "none");
278   system(buf);
279   was_filtered = is_filtered;
280 }
281
282 void *fb_flip_screen(void)
283 {
284   void *ret = bounce_buf;
285   void *s = bounce_buf;
286
287   switch (sw_filter) {
288   case SWFILTER_SCALE2X:
289     neon_scale2x_16_16(s, fb_current, src_w, src_w*2, src_w*2*2, src_h);
290     break;
291   case SWFILTER_SCALE3X:
292     neon_scale3x_16_16(s, fb_current, src_w, src_w*2, src_w*3*2, src_h);
293     break;
294   case SWFILTER_EAGLE2X:
295     neon_eagle2x_16_16(s, fb_current, src_w, src_w*2, src_w*2*2, src_h);
296     break;
297   case SWFILTER_NONE:
298   default:
299     break;
300   }
301
302   fb_current = vout_fbdev_flip(fb);
303   if (sw_filter == SWFILTER_NONE)
304     ret = fb_current;
305
306   return ret;
307 }
308
309 void fb_wait_vsync(void)
310 {
311   vout_fbdev_wait_vsync(fb);
312 }
313
314 void fb_set_mode(int w, int h, int buffers, int scale,
315  int filter, int filter2)
316 {
317   int lx, ly, lw = w, lh = h;
318   int multiplier;
319
320   switch (scale) {
321     case 0:
322       lw = w;
323       lh = h;
324       break;
325     case 1:
326       lw = w * 2;
327       lh = h * 2;
328       break;
329     case 2:
330       lw = w * 3;
331       lh = h * 3;
332       break;
333     case 3:
334       lw = 800;
335       lh = 480;
336       break;
337     case 15:
338       lw = 800;
339       lh = 480;
340       break;
341     default:
342       fprintf(stderr, "unknown scale: %d\n", scale);
343       break;
344   }
345   if (lw > 800)
346     lw = 800;
347   if (lh > 480)
348     lh = 480;
349   lx = 800 / 2 - lw / 2;
350   ly = 480 / 2 - lh / 2;
351
352   omap_setup_layer(vout_fbdev_get_fd(fb), 1, lx, ly, lw, lh);
353   set_filter(filter);
354
355   sw_filter = filter2;
356   if (w != 240) // menu
357     sw_filter = SWFILTER_SCALE2X;
358
359   switch (sw_filter) {
360   case SWFILTER_SCALE2X:
361     multiplier = 2;
362     break;
363   case SWFILTER_SCALE3X:
364     multiplier = 3;
365     break;
366   case SWFILTER_EAGLE2X:
367     multiplier = 2;
368     break;
369   case SWFILTER_NONE:
370   default:
371     multiplier = 1;
372     break;
373   }
374
375   fb_current = vout_fbdev_resize(fb, w * multiplier, h * multiplier,
376                                  16, 0, 0, 0, 0, buffers);
377   src_w = w;
378   src_h = h;
379 }
380
381 // vim:shiftwidth=2:expandtab