e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 Sam Lantinga |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | This library 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 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with this library; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
18 | |
19 | Sam Lantinga |
20 | slouken@libsdl.org |
21 | */ |
22 | #include "SDL_config.h" |
23 | |
24 | /* GGI-based SDL video driver implementation. |
25 | */ |
26 | |
27 | #include <fcntl.h> |
28 | #include <unistd.h> |
29 | #include <sys/mman.h> |
30 | |
31 | #include <ggi/ggi.h> |
32 | #include <ggi/gii.h> |
33 | |
34 | #include "SDL_video.h" |
35 | #include "SDL_mouse.h" |
36 | #include "../SDL_sysvideo.h" |
37 | #include "../SDL_pixels_c.h" |
38 | #include "../../events/SDL_events_c.h" |
39 | #include "SDL_ggivideo.h" |
40 | #include "SDL_ggimouse_c.h" |
41 | #include "SDL_ggievents_c.h" |
42 | |
43 | |
44 | struct private_hwdata |
45 | { |
46 | ggi_visual_t vis; |
47 | }; |
48 | |
49 | ggi_visual_t VIS; |
50 | |
51 | /* Initialization/Query functions */ |
52 | static int GGI_VideoInit(_THIS, SDL_PixelFormat *vformat); |
53 | static SDL_Rect **GGI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); |
54 | static SDL_Surface *GGI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); |
55 | static int GGI_SetColors(_THIS, int firstcolor, int ncolors, |
56 | SDL_Color *colors); |
57 | static void GGI_VideoQuit(_THIS); |
58 | |
59 | /* Hardware surface functions */ |
60 | static int GGI_AllocHWSurface(_THIS, SDL_Surface *surface); |
61 | static int GGI_LockHWSurface(_THIS, SDL_Surface *surface); |
62 | static void GGI_UnlockHWSurface(_THIS, SDL_Surface *surface); |
63 | static void GGI_FreeHWSurface(_THIS, SDL_Surface *surface); |
64 | |
65 | /* GGI driver bootstrap functions */ |
66 | |
67 | static int GGI_Available(void) |
68 | { |
69 | ggi_visual_t *vis; |
70 | |
71 | vis = NULL; |
72 | if (ggiInit() == 0) { |
73 | vis = ggiOpen(NULL); |
74 | if (vis != NULL) { |
75 | ggiClose(vis); |
76 | } |
77 | } |
78 | return (vis != NULL); |
79 | } |
80 | |
81 | static void GGI_DeleteDevice(SDL_VideoDevice *device) |
82 | { |
83 | SDL_free(device->hidden); |
84 | SDL_free(device); |
85 | } |
86 | |
87 | static SDL_VideoDevice *GGI_CreateDevice(int devindex) |
88 | { |
89 | SDL_VideoDevice *device; |
90 | |
91 | /* Initialize all variables that we clean on shutdown */ |
92 | device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice)); |
93 | if ( device ) { |
94 | SDL_memset(device, 0, (sizeof *device)); |
95 | device->hidden = (struct SDL_PrivateVideoData *) |
96 | SDL_malloc((sizeof *device->hidden)); |
97 | } |
98 | if ( (device == NULL) || (device->hidden == NULL) ) { |
99 | SDL_OutOfMemory(); |
100 | if ( device ) { |
101 | SDL_free(device); |
102 | } |
103 | return(0); |
104 | } |
105 | SDL_memset(device->hidden, 0, (sizeof *device->hidden)); |
106 | |
107 | /* Set the function pointers */ |
108 | device->VideoInit = GGI_VideoInit; |
109 | device->ListModes = GGI_ListModes; |
110 | device->SetVideoMode = GGI_SetVideoMode; |
111 | device->SetColors = GGI_SetColors; |
112 | device->UpdateRects = NULL; |
113 | device->VideoQuit = GGI_VideoQuit; |
114 | device->AllocHWSurface = GGI_AllocHWSurface; |
115 | device->CheckHWBlit = NULL; |
116 | device->FillHWRect = NULL; |
117 | device->SetHWColorKey = NULL; |
118 | device->SetHWAlpha = NULL; |
119 | device->LockHWSurface = GGI_LockHWSurface; |
120 | device->UnlockHWSurface = GGI_UnlockHWSurface; |
121 | device->FlipHWSurface = NULL; |
122 | device->FreeHWSurface = GGI_FreeHWSurface; |
123 | device->SetCaption = NULL; |
124 | device->SetIcon = NULL; |
125 | device->IconifyWindow = NULL; |
126 | device->GrabInput = NULL; |
127 | device->GetWMInfo = NULL; |
128 | device->InitOSKeymap = GGI_InitOSKeymap; |
129 | device->PumpEvents = GGI_PumpEvents; |
130 | |
131 | device->free = GGI_DeleteDevice; |
132 | |
133 | return device; |
134 | } |
135 | |
136 | VideoBootStrap GGI_bootstrap = { |
137 | "ggi", "General Graphics Interface (GGI)", |
138 | GGI_Available, GGI_CreateDevice |
139 | }; |
140 | |
141 | |
142 | static SDL_Rect video_mode; |
143 | static SDL_Rect *SDL_modelist[4] = { NULL, NULL, NULL, NULL }; |
144 | |
145 | int GGI_VideoInit(_THIS, SDL_PixelFormat *vformat) |
146 | { |
147 | ggi_mode mode = |
148 | { |
149 | 1, |
150 | { GGI_AUTO, GGI_AUTO }, |
151 | { GGI_AUTO, GGI_AUTO }, |
152 | { 0, 0 }, |
153 | GT_AUTO, |
154 | { GGI_AUTO, GGI_AUTO } |
155 | }; |
156 | struct private_hwdata *priv; |
157 | ggi_color pal[256], map[256]; |
158 | const ggi_directbuffer *db; |
159 | int err, num_bufs; |
160 | ggi_pixel white, black; |
161 | |
162 | priv = SDL_malloc(sizeof(struct private_hwdata)); |
163 | if (priv == NULL) |
164 | { |
165 | SDL_SetError("Unhandled GGI mode type!\n"); |
166 | GGI_VideoQuit(NULL); |
167 | } |
168 | |
169 | if (ggiInit() != 0) |
170 | { |
171 | SDL_SetError("Unable to initialize GGI!\n"); |
172 | GGI_VideoQuit(NULL); |
173 | } |
174 | |
175 | VIS = ggiOpen(NULL); |
176 | if (VIS == NULL) |
177 | { |
178 | SDL_SetError("Unable to open default GGI visual!\n"); |
179 | ggiExit(); |
180 | GGI_VideoQuit(NULL); |
181 | } |
182 | |
183 | ggiSetFlags(VIS, GGIFLAG_ASYNC); |
184 | |
185 | /* Validate mode, autodetecting any GGI_AUTO or GT_AUTO fields */ |
186 | ggiCheckMode(VIS, &mode); |
187 | |
188 | /* At this point we should have a valid mode - try to set it */ |
189 | err = ggiSetMode(VIS, &mode); |
190 | |
191 | /* If we couldn't set _any_ modes, something is very wrong */ |
192 | if (err) |
193 | { |
194 | SDL_SetError("Can't set a mode!\n"); |
195 | ggiClose(VIS); |
196 | ggiExit(); |
197 | GGI_VideoQuit(NULL); |
198 | } |
199 | |
200 | /* Determine the current screen size */ |
201 | this->info.current_w = mode.virt.x; |
202 | this->info.current_h = mode.virt.y; |
203 | |
204 | /* Set a palette for palletized modes */ |
205 | if (GT_SCHEME(mode.graphtype) == GT_PALETTE) |
206 | { |
207 | ggiSetColorfulPalette(VIS); |
208 | ggiGetPalette(VIS, 0, 1 << vformat->BitsPerPixel, pal); |
209 | } |
210 | |
211 | /* Now we try to get the DirectBuffer info, which determines whether |
212 | * SDL can access hardware surfaces directly. */ |
213 | |
214 | num_bufs = ggiDBGetNumBuffers(VIS); |
215 | |
216 | if (num_bufs > 0) |
217 | { |
218 | db = ggiDBGetBuffer(VIS, 0); /* Only handle one DB for now */ |
219 | |
220 | vformat->BitsPerPixel = db->buffer.plb.pixelformat->depth; |
221 | |
222 | vformat->Rmask = db->buffer.plb.pixelformat->red_mask; |
223 | vformat->Gmask = db->buffer.plb.pixelformat->green_mask; |
224 | vformat->Bmask = db->buffer.plb.pixelformat->blue_mask; |
225 | |
226 | /* Fill in our hardware acceleration capabilities */ |
227 | |
228 | this->info.wm_available = 0; |
229 | this->info.hw_available = 1; |
230 | this->info.video_mem = db->buffer.plb.stride * mode.virt.y; |
231 | } |
232 | |
233 | video_mode.x = 0; |
234 | video_mode.y = 0; |
235 | video_mode.w = mode.virt.x; |
236 | video_mode.h = mode.virt.y; |
237 | SDL_modelist[((vformat->BitsPerPixel + 7) / 8) - 1] = &video_mode; |
238 | |
239 | /* We're done! */ |
240 | return(0); |
241 | } |
242 | |
243 | static SDL_Rect **GGI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) |
244 | { |
245 | return(&SDL_modelist[((format->BitsPerPixel + 7) / 8) - 1]); |
246 | } |
247 | |
248 | /* Various screen update functions available */ |
249 | static void GGI_DirectUpdate(_THIS, int numrects, SDL_Rect *rects); |
250 | |
251 | SDL_Surface *GGI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags) |
252 | { |
253 | ggi_mode mode = |
254 | { |
255 | 1, |
256 | { GGI_AUTO, GGI_AUTO }, |
257 | { GGI_AUTO, GGI_AUTO }, |
258 | { 0, 0 }, |
259 | GT_AUTO, |
260 | { GGI_AUTO, GGI_AUTO } |
261 | }; |
262 | const ggi_directbuffer *db; |
263 | ggi_color pal[256]; |
264 | int err; |
265 | |
266 | fprintf(stderr, "GGI_SetVideoMode()\n"); |
267 | |
268 | mode.visible.x = mode.virt.x = width; |
269 | mode.visible.y = mode.virt.y = height; |
270 | |
271 | /* Translate requested SDL bit depth into a GGI mode */ |
272 | switch (bpp) |
273 | { |
274 | case 1: mode.graphtype = GT_1BIT; break; |
275 | case 2: mode.graphtype = GT_2BIT; break; |
276 | case 4: mode.graphtype = GT_4BIT; break; |
277 | case 8: mode.graphtype = GT_8BIT; break; |
278 | case 15: mode.graphtype = GT_15BIT; break; |
279 | case 16: mode.graphtype = GT_16BIT; break; |
280 | case 24: mode.graphtype = GT_24BIT; break; |
281 | case 32: mode.graphtype = GT_32BIT; break; |
282 | default: |
283 | SDL_SetError("Unknown SDL bit depth, using GT_AUTO....\n"); |
284 | mode.graphtype = GT_AUTO; |
285 | } |
286 | |
287 | /* Validate mode, autodetecting any GGI_AUTO or GT_AUTO fields */ |
288 | ggiCheckMode(VIS, &mode); |
289 | |
290 | /* At this point we should have a valid mode - try to set it */ |
291 | err = ggiSetMode(VIS, &mode); |
292 | |
293 | /* If we couldn't set _any_ modes, something is very wrong */ |
294 | if (err) |
295 | { |
296 | SDL_SetError("Can't set a mode!\n"); |
297 | ggiClose(VIS); |
298 | ggiExit(); |
299 | GGI_VideoQuit(NULL); |
300 | } |
301 | |
302 | /* Set a palette for palletized modes */ |
303 | if (GT_SCHEME(mode.graphtype) == GT_PALETTE) |
304 | { |
305 | ggiSetColorfulPalette(VIS); |
306 | ggiGetPalette(VIS, 0, 1 << bpp, pal); |
307 | } |
308 | |
309 | db = ggiDBGetBuffer(VIS, 0); |
310 | |
311 | /* Set up the new mode framebuffer */ |
312 | current->flags = (SDL_FULLSCREEN | SDL_HWSURFACE); |
313 | current->w = mode.virt.x; |
314 | current->h = mode.virt.y; |
315 | current->pitch = db->buffer.plb.stride; |
316 | current->pixels = db->read; |
317 | |
318 | /* Set the blit function */ |
319 | this->UpdateRects = GGI_DirectUpdate; |
320 | |
321 | /* We're done */ |
322 | return(current); |
323 | } |
324 | |
325 | static int GGI_AllocHWSurface(_THIS, SDL_Surface *surface) |
326 | { |
327 | return(-1); |
328 | } |
329 | static void GGI_FreeHWSurface(_THIS, SDL_Surface *surface) |
330 | { |
331 | return; |
332 | } |
333 | static int GGI_LockHWSurface(_THIS, SDL_Surface *surface) |
334 | { |
335 | return(0); |
336 | } |
337 | static void GGI_UnlockHWSurface(_THIS, SDL_Surface *surface) |
338 | { |
339 | return; |
340 | } |
341 | |
342 | static void GGI_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) |
343 | { |
344 | int i; |
345 | |
346 | /* ggiFlush(VIS); */ |
347 | |
348 | for (i = 0; i < numrects; i++) |
349 | { |
350 | ggiFlushRegion(VIS, rects[i].x, rects[i].y, rects[i].w, rects[i].h); |
351 | } |
352 | return; |
353 | } |
354 | |
355 | int GGI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) |
356 | { |
357 | int i; |
358 | ggi_color pal[256]; |
359 | |
360 | /* Set up the colormap */ |
361 | for (i = 0; i < ncolors; i++) |
362 | { |
363 | pal[i].r = (colors[i].r << 8) | colors[i].r; |
364 | pal[i].g = (colors[i].g << 8) | colors[i].g; |
365 | pal[i].b = (colors[i].b << 8) | colors[i].b; |
366 | } |
367 | |
368 | ggiSetPalette(VIS, firstcolor, ncolors, pal); |
369 | |
370 | return 1; |
371 | } |
372 | |
373 | void GGI_VideoQuit(_THIS) |
374 | { |
375 | } |
376 | void GGI_FinalQuit(void) |
377 | { |
378 | } |