comparison src/video/wscons/SDL_wsconsvideo.c @ 1187:19d8949b4584

To: sdl@libsdl.org From: Staffan Ulfberg <staffan@ulfberg.se> Date: 19 Nov 2005 01:00:48 +0100 Subject: [SDL] New driver for OpenBSD/wscons Hello, I've written an SDL driver for OpenBSD/wscons (console mode, somewhat resembling the functionality of the svga driver for Linux). I use it for playing MAME on my Sharp Zaurus. The alternative is to play under X, which is slower. I asked how to submit the driver a few days ago, and posted a link to the patch in a follow-up, so maybe it was missed? Anyway, the patch is on the web at: http://multivac.fatburen.org/SDL-wscons.patch Comments? Staffan
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 22 Nov 2005 15:19:50 +0000
parents
children c9b51268668f
comparison
equal deleted inserted replaced
1186:0276947bee66 1187:19d8949b4584
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2004 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 #include <sys/time.h>
29 #include <sys/mman.h>
30 #include <sys/ioctl.h>
31 #include <dev/wscons/wsdisplay_usl_io.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <errno.h>
39
40 #include "SDL.h"
41 #include "SDL_error.h"
42 #include "SDL_video.h"
43 #include "SDL_mouse.h"
44 #include "SDL_sysvideo.h"
45 #include "SDL_pixels_c.h"
46 #include "SDL_events_c.h"
47
48 #include "SDL_wsconsvideo.h"
49 #include "SDL_wsconsevents_c.h"
50 #include "SDL_wsconsmouse_c.h"
51
52 #define WSCONSVID_DRIVER_NAME "wscons"
53 enum {
54 WSCONS_ROTATE_NONE = 0,
55 WSCONS_ROTATE_CCW = 90,
56 WSCONS_ROTATE_UD = 180,
57 WSCONS_ROTATE_CW = 270
58 };
59
60 #define min(a,b) ((a)<(b)?(a):(b))
61
62 /* Initialization/Query functions */
63 static int WSCONS_VideoInit(_THIS, SDL_PixelFormat *vformat);
64 static SDL_Rect **WSCONS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
65 static SDL_Surface *WSCONS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
66 static int WSCONS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
67 static void WSCONS_VideoQuit(_THIS);
68
69 /* Hardware surface functions */
70 static int WSCONS_AllocHWSurface(_THIS, SDL_Surface *surface);
71 static int WSCONS_LockHWSurface(_THIS, SDL_Surface *surface);
72 static void WSCONS_UnlockHWSurface(_THIS, SDL_Surface *surface);
73 static void WSCONS_FreeHWSurface(_THIS, SDL_Surface *surface);
74
75 /* etc. */
76 static WSCONS_bitBlit WSCONS_blit16;
77 static WSCONS_bitBlit WSCONS_blit16blocked;
78 static void WSCONS_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
79
80 void WSCONS_ReportError(char *fmt, ...)
81 {
82 char message[200];
83
84 message[199] = '\0';
85
86 va_list vaArgs;
87 va_start(vaArgs, fmt);
88 vsnprintf(message, 199, fmt, vaArgs);
89 va_end(vaArgs);
90
91 SDL_SetError(message);
92 fprintf(stderr, "WSCONS error: %s\n", message);
93 }
94
95 /* WSCONS driver bootstrap functions */
96
97 static int WSCONS_Available(void)
98 {
99 return 1;
100 }
101
102 static void WSCONS_DeleteDevice(SDL_VideoDevice *device)
103 {
104 free(device->hidden);
105 free(device);
106 }
107
108 static SDL_VideoDevice *WSCONS_CreateDevice(int devindex)
109 {
110 SDL_VideoDevice *device;
111
112 /* Initialize all variables that we clean on shutdown */
113 device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
114 if (device == NULL) {
115 SDL_OutOfMemory();
116 return 0;
117 }
118 memset(device, 0, (sizeof *device));
119 device->hidden =
120 (struct SDL_PrivateVideoData *)malloc((sizeof *device->hidden));
121 if (device->hidden == NULL) {
122 SDL_OutOfMemory();
123 free(device);
124 return(0);
125 }
126 memset(device->hidden, 0, (sizeof *device->hidden));
127 device->hidden->fd = -1;
128
129 /* Set the function pointers */
130 device->VideoInit = WSCONS_VideoInit;
131 device->ListModes = WSCONS_ListModes;
132 device->SetVideoMode = WSCONS_SetVideoMode;
133 device->SetColors = WSCONS_SetColors;
134 device->UpdateRects = WSCONS_UpdateRects;
135 device->VideoQuit = WSCONS_VideoQuit;
136 device->AllocHWSurface = WSCONS_AllocHWSurface;
137 device->LockHWSurface = WSCONS_LockHWSurface;
138 device->UnlockHWSurface = WSCONS_UnlockHWSurface;
139 device->FreeHWSurface = WSCONS_FreeHWSurface;
140 device->InitOSKeymap = WSCONS_InitOSKeymap;
141 device->PumpEvents = WSCONS_PumpEvents;
142 device->free = WSCONS_DeleteDevice;
143
144 return device;
145 }
146
147 VideoBootStrap WSCONS_bootstrap = {
148 WSCONSVID_DRIVER_NAME,
149 "SDL wscons video driver",
150 WSCONS_Available,
151 WSCONS_CreateDevice
152 };
153
154 #define WSCONSDEV_FORMAT "/dev/ttyC%01x"
155
156 int WSCONS_VideoInit(_THIS, SDL_PixelFormat *vformat)
157 {
158 char devnamebuf[30];
159 char *devname;
160 char *rotation;
161 int wstype;
162 int wsmode = WSDISPLAYIO_MODE_DUMBFB;
163 size_t len, mapsize;
164 int pagemask;
165 int width, height;
166
167 devname = getenv("SDL_WSCONSDEV");
168 if (devname == NULL) {
169 int activeVT;
170 if (ioctl(STDIN_FILENO, VT_GETACTIVE, &activeVT) == -1) {
171 WSCONS_ReportError("Unable to determine active terminal: %s",
172 strerror(errno));
173 return -1;
174 }
175 snprintf(devnamebuf, sizeof(devnamebuf), WSCONSDEV_FORMAT, activeVT - 1);
176 devname = devnamebuf;
177 }
178
179 private->fd = open(devname, O_RDWR | O_NONBLOCK, 0);
180 if (private->fd == -1) {
181 WSCONS_ReportError("open %s: %s", devname, strerror(errno));
182 return -1;
183 }
184 if (ioctl(private->fd, WSDISPLAYIO_GINFO, &private->info) == -1) {
185 WSCONS_ReportError("ioctl WSDISPLAY_GINFO: %s", strerror(errno));
186 return -1;
187 }
188 if (ioctl(private->fd, WSDISPLAYIO_GTYPE, &wstype) == -1) {
189 WSCONS_ReportError("ioctl WSDISPLAY_GTYPE: %s", strerror(errno));
190 return -1;
191 }
192 if (ioctl(private->fd, WSDISPLAYIO_LINEBYTES, &private->physlinebytes) == -1) {
193 WSCONS_ReportError("ioctl WSDISPLAYIO_LINEBYTES: %s", strerror(errno));
194 return -1;
195 }
196 if (private->info.depth > 8) {
197 if (wstype == WSDISPLAY_TYPE_SUN24 ||
198 wstype == WSDISPLAY_TYPE_SUNCG12 ||
199 wstype == WSDISPLAY_TYPE_SUNCG14 ||
200 wstype == WSDISPLAY_TYPE_SUNTCX ||
201 wstype == WSDISPLAY_TYPE_SUNFFB) {
202 private->redMask = 0x0000ff;
203 private->greenMask = 0x00ff00;
204 private->blueMask = 0xff0000;
205 } else if (wstype == WSDISPLAY_TYPE_PXALCD) {
206 private->redMask = 0x1f << 11;
207 private->greenMask = 0x3f << 5;
208 private->blueMask = 0x1f;
209 } else {
210 WSCONS_ReportError("Unknown video hardware");
211 return -1;
212 }
213 } else {
214 WSCONS_ReportError("Displays with 8 bpp or less are not supported");
215 return -1;
216 }
217
218 private->rotate = WSCONS_ROTATE_NONE;
219 rotation = getenv("SDL_VIDEO_WSCONS_ROTATION");
220 if (rotation != NULL) {
221 if (strlen(rotation) == 0) {
222 private->shadowFB = 0;
223 private->rotate = WSCONS_ROTATE_NONE;
224 printf("Not rotating, no shadow\n");
225 } else if (!strcmp(rotation, "NONE")) {
226 private->shadowFB = 1;
227 private->rotate = WSCONS_ROTATE_NONE;
228 printf("Not rotating, but still using shadow\n");
229 } else if (!strcmp(rotation, "CW")) {
230 private->shadowFB = 1;
231 private->rotate = WSCONS_ROTATE_CW;
232 printf("Rotating screen clockwise\n");
233 } else if (!strcmp(rotation, "CCW")) {
234 private->shadowFB = 1;
235 private->rotate = WSCONS_ROTATE_CCW;
236 printf("Rotating screen counter clockwise\n");
237 } else if (!strcmp(rotation, "UD")) {
238 private->shadowFB = 1;
239 private->rotate = WSCONS_ROTATE_UD;
240 printf("Rotating screen upside down\n");
241 } else {
242 WSCONS_ReportError("\"%s\" is not a valid value for "
243 "SDL_VIDEO_WSCONS_ROTATION", rotation);
244 return -1;
245 }
246 }
247
248 switch (private->info.depth) {
249 case 1:
250 case 4:
251 case 8:
252 len = private->physlinebytes * private->info.height;
253 break;
254 case 16:
255 if (private->physlinebytes == private->info.width) {
256 len = private->info.width * private->info.height * sizeof(short);
257 } else {
258 len = private->physlinebytes * private->info.height;
259 }
260 if (private->rotate == WSCONS_ROTATE_NONE ||
261 private->rotate == WSCONS_ROTATE_UD) {
262 private->blitFunc = WSCONS_blit16;
263 } else {
264 private->blitFunc = WSCONS_blit16blocked;
265 }
266 break;
267 case 32:
268 if (private->physlinebytes == private->info.width) {
269 len = private->info.width * private->info.height * sizeof(int);
270 } else {
271 len = private->physlinebytes * private->info.height;
272 }
273 break;
274 default:
275 WSCONS_ReportError("unsupported depth %d", private->info.depth);
276 return -1;
277 }
278
279 if (private->shadowFB && private->blitFunc == NULL) {
280 WSCONS_ReportError("Using software buffer, but no blitter function is "
281 "available for this %d bpp.", private->info.depth);
282 return -1;
283 }
284
285 if (ioctl(private->fd, WSDISPLAYIO_SMODE, &wsmode) == -1) {
286 WSCONS_ReportError("ioctl SMODE");
287 return -1;
288 }
289
290 pagemask = getpagesize() - 1;
291 mapsize = ((int)len + pagemask) & ~pagemask;
292 private->physmem = (Uint8 *)mmap(NULL, mapsize,
293 PROT_READ | PROT_WRITE, MAP_SHARED,
294 private->fd, (off_t)0);
295 if (private->physmem == (Uint8 *)MAP_FAILED) {
296 private->physmem = NULL;
297 WSCONS_ReportError("mmap: %s", strerror(errno));
298 return -1;
299 }
300 private->fbmem_len = len;
301
302 if (private->rotate == WSCONS_ROTATE_CW ||
303 private->rotate == WSCONS_ROTATE_CCW) {
304 width = private->info.height;
305 height = private->info.width;
306 } else {
307 width = private->info.width;
308 height = private->info.height;
309 }
310
311 if (private->shadowFB) {
312 private->shadowmem = (Uint8 *)malloc(len);
313 if (private->shadowmem == NULL) {
314 WSCONS_ReportError("No memory for shadow");
315 return -1;
316 }
317 private->fbstart = private->shadowmem;
318 private->fblinebytes = width * ((private->info.depth + 7) / 8);
319 } else {
320 private->fbstart = private->physmem;
321 private->fblinebytes = private->physlinebytes;
322 }
323
324 private->SDL_modelist[0] = (SDL_Rect *)malloc(sizeof(SDL_Rect));
325 private->SDL_modelist[0]->w = width;
326 private->SDL_modelist[0]->h = height;
327
328 vformat->BitsPerPixel = private->info.depth;
329 vformat->BytesPerPixel = private->info.depth / 8;
330
331 if (WSCONS_InitKeyboard(this) == -1) {
332 return -1;
333 }
334
335 return 0;
336 }
337
338 SDL_Rect **WSCONS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
339 {
340 if (format->BitsPerPixel == private->info.depth) {
341 return private->SDL_modelist;
342 } else {
343 return NULL;
344 }
345 }
346
347 SDL_Surface *WSCONS_SetVideoMode(_THIS, SDL_Surface *current,
348 int width, int height, int bpp, Uint32 flags)
349 {
350 if (width != private->SDL_modelist[0]->w ||
351 height != private->SDL_modelist[0]->h) {
352 WSCONS_ReportError("Requested video mode %dx%d not supported.",
353 width, height);
354 return NULL;
355 }
356 if (bpp != private->info.depth) {
357 WSCONS_ReportError("Requested video depth %d bpp not supported.", bpp);
358 return NULL;
359 }
360
361 if (!SDL_ReallocFormat(current,
362 bpp,
363 private->redMask,
364 private->greenMask,
365 private->blueMask,
366 0)) {
367 WSCONS_ReportError("Couldn't allocate new pixel format");
368 return NULL;
369 }
370
371 current->flags &= SDL_FULLSCREEN;
372 if (private->shadowFB) {
373 current->flags |= SDL_SWSURFACE;
374 } else {
375 current->flags |= SDL_HWSURFACE;
376 }
377 current->w = width;
378 current->h = height;
379 current->pitch = private->fblinebytes;
380 current->pixels = private->fbstart;
381
382 memset(private->fbstart, 0, private->fbmem_len);
383
384 return current;
385 }
386
387 static int WSCONS_AllocHWSurface(_THIS, SDL_Surface *surface)
388 {
389 return -1;
390 }
391 static void WSCONS_FreeHWSurface(_THIS, SDL_Surface *surface)
392 {
393 }
394
395 static int WSCONS_LockHWSurface(_THIS, SDL_Surface *surface)
396 {
397 return 0;
398 }
399
400 static void WSCONS_UnlockHWSurface(_THIS, SDL_Surface *surface)
401 {
402 }
403
404 static void WSCONS_blit16(Uint8 *byte_src_pos,
405 int srcRightDelta,
406 int srcDownDelta,
407 Uint8 *byte_dst_pos,
408 int dst_linebytes,
409 int width,
410 int height)
411 {
412 int w;
413 Uint16 *src_pos = (Uint16 *)byte_src_pos;
414 Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
415
416 while (height) {
417 Uint16 *src = src_pos;
418 Uint16 *dst = dst_pos;
419 for (w = width; w != 0; w--) {
420 *dst = *src;
421 src += srcRightDelta;
422 dst++;
423 }
424 dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes);
425 src_pos += srcDownDelta;
426 height--;
427 }
428 }
429
430 #define BLOCKSIZE_W 32
431 #define BLOCKSIZE_H 32
432
433 static void WSCONS_blit16blocked(Uint8 *byte_src_pos,
434 int srcRightDelta,
435 int srcDownDelta,
436 Uint8 *byte_dst_pos,
437 int dst_linebytes,
438 int width,
439 int height)
440 {
441 int w;
442 Uint16 *src_pos = (Uint16 *)byte_src_pos;
443 Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
444
445 while (height > 0) {
446 Uint16 *src = src_pos;
447 Uint16 *dst = dst_pos;
448 for (w = width; w > 0; w -= BLOCKSIZE_W) {
449 WSCONS_blit16((Uint8 *)src,
450 srcRightDelta,
451 srcDownDelta,
452 (Uint8 *)dst,
453 dst_linebytes,
454 min(w, BLOCKSIZE_W),
455 min(height, BLOCKSIZE_H));
456 src += srcRightDelta * BLOCKSIZE_W;
457 dst += BLOCKSIZE_W;
458 }
459 dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes * BLOCKSIZE_H);
460 src_pos += srcDownDelta * BLOCKSIZE_H;
461 height -= BLOCKSIZE_H;
462 }
463 }
464
465 static void WSCONS_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
466 {
467 int width = private->SDL_modelist[0]->w;
468 int height = private->SDL_modelist[0]->h;
469 int bytesPerPixel = (private->info.depth + 7) / 8;
470 int i;
471
472 if (!private->shadowFB) {
473 return;
474 }
475
476 if (private->info.depth != 16) {
477 WSCONS_ReportError("Shadow copy only implemented for 16 bpp");
478 return;
479 }
480
481 for (i = 0; i < numrects; i++) {
482 int x1, y1, x2, y2;
483 int scr_x1, scr_y1, scr_x2, scr_y2;
484 int sha_x1, sha_y1;
485 int shadowRightDelta; /* Address change when moving right in dest */
486 int shadowDownDelta; /* Address change when moving down in dest */
487 Uint8 *src_start;
488 Uint8 *dst_start;
489
490 x1 = rects[i].x;
491 y1 = rects[i].y;
492 x2 = x1 + rects[i].w;
493 y2 = y1 + rects[i].h;
494
495 if (x1 < 0) {
496 x1 = 0;
497 } else if (x1 > width) {
498 x1 = width;
499 }
500 if (x2 < 0) {
501 x2 = 0;
502 } else if (x2 > width) {
503 x2 = width;
504 }
505 if (y1 < 0) {
506 y1 = 0;
507 } else if (y1 > height) {
508 y1 = height;
509 }
510 if (y2 < 0) {
511 y2 = 0;
512 } else if (y2 > height) {
513 y2 = height;
514 }
515 if (x2 <= x1 || y2 <= y1) {
516 continue;
517 }
518
519 switch (private->rotate) {
520 case WSCONS_ROTATE_NONE:
521 sha_x1 = scr_x1 = x1;
522 sha_y1 = scr_y1 = y1;
523 scr_x2 = x2;
524 scr_y2 = y2;
525 shadowRightDelta = 1;
526 shadowDownDelta = width;
527 break;
528 case WSCONS_ROTATE_CCW:
529 scr_x1 = y1;
530 scr_y1 = width - x2;
531 scr_x2 = y2;
532 scr_y2 = width - x1;
533 sha_x1 = x2 - 1;
534 sha_y1 = y1;
535 shadowRightDelta = width;
536 shadowDownDelta = -1;
537 break;
538 case WSCONS_ROTATE_UD:
539 scr_x1 = width - x2;
540 scr_y1 = height - y2;
541 scr_x2 = width - x1;
542 scr_y2 = height - y1;
543 sha_x1 = x2 - 1;
544 sha_y1 = y2 - 1;
545 shadowRightDelta = -1;
546 shadowDownDelta = -width;
547 break;
548 case WSCONS_ROTATE_CW:
549 scr_x1 = height - y2;
550 scr_y1 = x1;
551 scr_x2 = height - y1;
552 scr_y2 = x2;
553 sha_x1 = x1;
554 sha_y1 = y2 - 1;
555 shadowRightDelta = -width;
556 shadowDownDelta = 1;
557 break;
558 default:
559 WSCONS_ReportError("Unknown rotation");
560 return;
561 }
562
563 src_start = private->shadowmem + (sha_y1 * width + sha_x1) * bytesPerPixel;
564 dst_start = private->physmem + scr_y1 * private->physlinebytes +
565 scr_x1 * bytesPerPixel;
566
567 private->blitFunc(src_start,
568 shadowRightDelta,
569 shadowDownDelta,
570 dst_start,
571 private->physlinebytes,
572 scr_x2 - scr_x1,
573 scr_y2 - scr_y1);
574 }
575 }
576
577 int WSCONS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
578 {
579 return 0;
580 }
581
582 /*
583 * Note: If we are terminated, this could be called in the middle of
584 * another SDL video routine -- notably UpdateRects.
585 */
586 void WSCONS_VideoQuit(_THIS)
587 {
588 int mode = WSDISPLAYIO_MODE_EMUL;
589
590 if (private->shadowmem != NULL) {
591 free(private->shadowmem);
592 private->shadowmem = NULL;
593 }
594 private->fbstart = NULL;
595 if (this->screen != NULL) {
596 this->screen->pixels = NULL;
597 }
598
599 if (private->SDL_modelist[0] != NULL) {
600 free(private->SDL_modelist[0]);
601 private->SDL_modelist[0] = NULL;
602 }
603
604 if (ioctl(private->fd, WSDISPLAYIO_SMODE, &mode) == -1) {
605 WSCONS_ReportError("ioctl SMODE");
606 }
607
608 WSCONS_ReleaseKeyboard(this);
609
610 if (private->fd != -1) {
611 close(private->fd);
612 private->fd = -1;
613 }
614 }