src/platform/sdl/pandora-sdl.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "main.h"
7
8#include "gba/supervisor/thread.h"
9
10#include <linux/omapfb.h>
11#include <linux/fb.h>
12#include <sys/ioctl.h>
13#include <sys/mman.h>
14
15#ifndef FBIO_WAITFORVSYNC
16#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
17#endif
18
19static bool GBASDLInit(struct SDLSoftwareRenderer* renderer);
20static void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
21static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer);
22
23void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) {
24 renderer->init = GBASDLInit;
25 renderer->deinit = GBASDLDeinit;
26 renderer->runloop = GBASDLRunloop;
27}
28
29void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer) {
30 renderer->init = GBASDLInit;
31 renderer->deinit = GBASDLDeinit;
32 renderer->runloop = GBASDLRunloop;
33}
34
35bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
36 SDL_SetVideoMode(800, 480, 16, SDL_FULLSCREEN);
37
38 renderer->odd = 0;
39 renderer->fb = open("/dev/fb1", O_RDWR);
40 if (renderer->fb < 0) {
41 return false;
42 }
43
44 struct omapfb_plane_info plane;
45 struct omapfb_mem_info mem;
46 if (ioctl(renderer->fb, OMAPFB_QUERY_PLANE, &plane) < 0) {
47 return false;
48 }
49 if (ioctl(renderer->fb, OMAPFB_QUERY_MEM, &mem) < 0) {
50 return false;
51 }
52
53 if (plane.enabled) {
54 plane.enabled = 0;
55 ioctl(renderer->fb, OMAPFB_SETUP_PLANE, &plane);
56 }
57
58 mem.size = VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4;
59 ioctl(renderer->fb, OMAPFB_SETUP_MEM, &mem);
60
61 plane.enabled = 1;
62 plane.pos_x = 40;
63 plane.pos_y = 0;
64 plane.out_width = 720;
65 plane.out_height = 480;
66 ioctl(renderer->fb, OMAPFB_SETUP_PLANE, &plane);
67
68 struct fb_var_screeninfo info;
69 ioctl(renderer->fb, FBIOGET_VSCREENINFO, &info);
70 info.xres = VIDEO_HORIZONTAL_PIXELS;
71 info.yres = VIDEO_VERTICAL_PIXELS;
72 info.xres_virtual = VIDEO_HORIZONTAL_PIXELS;
73 info.yres_virtual = VIDEO_VERTICAL_PIXELS * 2;
74 info.bits_per_pixel = 16;
75 ioctl(renderer->fb, FBIOPUT_VSCREENINFO, &info);
76
77 renderer->odd = 0;
78 renderer->base[0] = mmap(0, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4, PROT_READ | PROT_WRITE, MAP_SHARED, renderer->fb, 0);
79 renderer->base[1] = (uint16_t*) renderer->base[0] + VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS;
80
81 renderer->d.outputBuffer = renderer->base[0];
82 renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
83 return true;
84}
85
86void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
87 SDL_Event event;
88
89 while (context->state < THREAD_EXITING) {
90 while (SDL_PollEvent(&event)) {
91 GBASDLHandleEvent(context, &renderer->player, &event);
92 }
93
94 if (GBASyncWaitFrameStart(&context->sync)) {
95 struct fb_var_screeninfo info;
96 ioctl(renderer->fb, FBIOGET_VSCREENINFO, &info);
97 info.yoffset = VIDEO_VERTICAL_PIXELS * renderer->odd;
98 ioctl(renderer->fb, FBIOPAN_DISPLAY, &info);
99
100 int arg = 0;
101 ioctl(renderer->fb, FBIO_WAITFORVSYNC, &arg);
102
103 renderer->odd = !renderer->odd;
104 renderer->d.outputBuffer = renderer->base[renderer->odd];
105 }
106 GBASyncWaitFrameEnd(&context->sync);
107 }
108}
109
110void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
111 munmap(renderer->base[0], VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
112
113 struct omapfb_plane_info plane;
114 struct omapfb_mem_info mem;
115 ioctl(renderer->fb, OMAPFB_QUERY_PLANE, &plane);
116 ioctl(renderer->fb, OMAPFB_QUERY_MEM, &mem);
117
118 mem.size = 0;
119 ioctl(renderer->fb, OMAPFB_SETUP_MEM, &mem);
120
121 plane.enabled = 0;
122 plane.pos_x = 0;
123 plane.pos_y = 0;
124 plane.out_width = 0;
125 plane.out_height = 0;
126 ioctl(renderer->fb, OMAPFB_SETUP_PLANE, &plane);
127
128 close(renderer->fb);
129}