integrate M-HT's neon scalers
[gpsp.git] / pandora / pnd.c
CommitLineData
eb3668fc 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
e38fee1b 28#include "../arm/neon_scale2x.h"
29#include "../arm/neon_scale3x.h"
30#include "../arm/neon_eagle2x.h"
eb3668fc 31#include "linux/fbdev.h"
32#include "linux/xenv.h"
33
34enum 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
54u32 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
75u32 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
96static const u32 xk_to_gkey[] = {
97 XK_Up, XK_Left, XK_Down, XK_Right, XK_Alt_L, XK_Control_L,
931b76c0 98 XK_Shift_R, XK_Control_R, XK_Home, XK_End, XK_Page_Down, XK_Page_Up,
eb3668fc 99 XK_1, XK_2, XK_3, XK_4, XK_space,
100};
101
102static 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
108struct vout_fbdev *fb;
e38fee1b 109static void *fb_current;
110static int bounce_buf[400 * 272 * 2 / 4];
111static int src_w = 240, src_h = 160;
112static 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
eb3668fc 122
5b5ebfc1 123static int omap_setup_layer(int fd, int enabled, int x, int y, int w, int h)
eb3668fc 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
e38fee1b 149 /* alloc enough for 3x scaled tripple buffering */
150 if (mi.size < MAX_VRAM_SIZE) {
151 mi.size = MAX_VRAM_SIZE;
eb3668fc 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
174void 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
5b5ebfc1 203 ret = omap_setup_layer(fd, 0, 0, 0, 400, 272);
eb3668fc 204 close(fd);
205 if (ret != 0) {
206 fprintf(stderr, "failed to set up layer, exiting.\n");
207 exit(1);
208 }
209
e38fee1b 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);
eb3668fc 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
223void gpsp_plat_quit(void)
224{
225 xenv_finish();
5b5ebfc1 226 omap_setup_layer(vout_fbdev_get_fd(fb), 0, 0, 0, 0, 0);
eb3668fc 227 vout_fbdev_finish(fb);
228 SDL_Quit();
229}
230
231u32 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
255u32 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
268static 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
282void *fb_flip_screen(void)
283{
e38fee1b 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;
eb3668fc 307}
308
309void fb_wait_vsync(void)
310{
311 vout_fbdev_wait_vsync(fb);
312}
313
e38fee1b 314void fb_set_mode(int w, int h, int buffers, int scale,
315 int filter, int filter2)
eb3668fc 316{
317 int lx, ly, lw = w, lh = h;
e38fee1b 318 int multiplier;
319
eb3668fc 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:
e38fee1b 338 lw = 800;
339 lh = 480;
eb3668fc 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
5b5ebfc1 352 omap_setup_layer(vout_fbdev_get_fd(fb), 1, lx, ly, lw, lh);
eb3668fc 353 set_filter(filter);
354
e38fee1b 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;
eb3668fc 379}
380
381// vim:shiftwidth=2:expandtab