standalone: refactor for becoming also a SDL driver
[sdl_omap.git] / src / video / omapdss / standalone.c
CommitLineData
b78828bf 1/*
2 * (C) notaz, 2010
3 *
4 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
0ec348b9 8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/time.h>
12#include <SDL/SDL.h>
13
b78828bf 14#include "omapsdl.h"
3cb98c5e 15#include "common/input.h"
0ec348b9 16#include "linux/fbdev.h"
3cb98c5e 17#include "linux/oshide.h"
0ec348b9 18
19static SDL_Surface *g_screen;
20static void *g_screen_fbp;
21static Uint16 g_8bpp_pal[256];
22static Uint32 g_start_ticks;
0ec348b9 23
24static inline int min(int v1, int v2)
25{
26 return v1 < v2 ? v1 : v2;
27}
28
0ec348b9 29static SDL_Surface *alloc_surface(int w, int h, int bpp)
30{
31 // SDL has some pointer overuse, every surface has a format,
32 // why make format accessible through pointer?
33 struct {
34 SDL_Surface s;
35 SDL_PixelFormat f;
36 } *ret;
37
38 ret = calloc(1, sizeof(*ret));
39 if (ret == NULL)
40 return NULL;
41
42 ret->s.format = &ret->f;
43 ret->f.BitsPerPixel = bpp;
44 ret->f.BytesPerPixel = (bpp + 7) / 8;
45
46 ret->s.w = w;
47 ret->s.h = h;
48 ret->s.pitch = w * ret->f.BytesPerPixel;
49 // XXX: more fields
50
51 return &ret->s;
52}
53
54DECLSPEC int SDLCALL
55SDL_Init(Uint32 flags)
56{
57 trace("%08x", flags);
58
3cb98c5e 59 if (g_start_ticks == 0) {
b78828bf 60 omapsdl_input_init();
3cb98c5e 61 oshide_init();
b78828bf 62 omapsdl_config();
3cb98c5e 63 }
64
0ec348b9 65 g_start_ticks = 0;
66 g_start_ticks = SDL_GetTicks();
67
68 return 0;
69}
70
71DECLSPEC void SDLCALL
72SDL_Quit(void)
73{
74 trace("");
3cb98c5e 75
76 if (g_start_ticks != 0) {
77 oshide_finish();
78 g_start_ticks = 0;
79 }
0ec348b9 80}
81
82DECLSPEC int SDLCALL
83SDL_InitSubSystem(Uint32 flags)
84{
85 trace("%08x", flags);
86 return 0;
87}
88
89DECLSPEC void SDLCALL
90SDL_QuitSubSystem(Uint32 flags)
91{
92 trace("%08x", flags);
93}
94
95DECLSPEC Uint32 SDLCALL
96SDL_GetTicks(void)
97{
98 struct timeval tv;
99 Uint32 ret;
100
101 gettimeofday(&tv, NULL);
102 ret = tv.tv_sec * 1000;
103 ret += tv.tv_usec * 1048 >> 20;
104
105 ret -= g_start_ticks;
106 dbg(" SDL_GetTicks %d", ret);
107 return ret;
108}
109
110DECLSPEC SDL_Surface * SDLCALL
111SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
112{
113 struct vout_fbdev *fbdev;
114
115 trace("%d, %d, %d, %08x", width, height, bpp, flags);
116
3cb98c5e 117 if (bpp == 0)
118 bpp = 16;
119
0ec348b9 120 if (bpp != 8 && bpp != 16) {
121 err("unsupported bpp: %d\n", bpp);
122 return NULL;
123 }
124
125 // XXX: destroy old g_screen?
126
127 g_screen = alloc_surface(width, height, bpp);
128 if (g_screen == NULL)
129 return NULL;
130
131 fbdev = vout_fbdev_init("/dev/fb0", &width, &height, 0);
132 if (fbdev == NULL)
133 goto fail_fbdev_init;
134
135 g_screen_fbp = vout_fbdev_flip(fbdev);
136 if (bpp == 16)
137 g_screen->pixels = g_screen_fbp;
138 else
139 // we have to fake this for now..
140 g_screen->pixels = calloc(g_screen->pitch * height, 1);
141
142 if (g_screen->pixels == NULL) {
143 err("fb NULL");
144 goto fail_pixels;
145 }
146 g_screen->hwdata = (void *)fbdev;
147
148 dbg("returning %p", g_screen);
149 return g_screen;
150
151fail_pixels:
152 vout_fbdev_finish(fbdev);
153fail_fbdev_init:
154 free(g_screen);
155 g_screen = NULL;
156 return NULL;
157}
158
159DECLSPEC int SDLCALL
160SDL_Flip(SDL_Surface *screen)
161{
162 struct vout_fbdev *fbdev;
163
164 trace("%p", screen);
165
166 if (screen != g_screen) {
167 err("flip not on screen surface?");
168 return -1;
169 }
170
171 if (screen->format->BitsPerPixel == 8) {
172 int l = screen->pitch * screen->h;
3cb98c5e 173#ifdef __arm__
0ec348b9 174 do_clut(g_screen_fbp, screen->pixels, g_8bpp_pal, l);
175#else
176 Uint16 *d = g_screen_fbp;
177 Uint8 *s = screen->pixels;
178
179 // XXX: perhaps optimize this sh*t
180 for (; l > 0; d++, s++, l--)
181 *d = g_8bpp_pal[*s];
182#endif
183 }
184
185 fbdev = (void *)screen->hwdata;
186 g_screen_fbp = vout_fbdev_flip(fbdev);
187
188 if (screen->format->BitsPerPixel != 8)
189 screen->pixels = g_screen_fbp;
190
191 return 0;
192}
193
194static int do_rect_clip(const SDL_Surface *s, SDL_Rect *r)
195{
196 int x = r->x, y = r->y, w = r->w, h = r->h;
197
198 if (x < 0) {
199 w += x;
200 if (w < 0)
201 w = 0;
202 x = 0;
203 }
204 if (y < 0) {
205 h += y;
206 if (h < 0)
207 h = 0;
208 y = 0;
209 }
210 if (x + w > s->w) {
211 w = s->w - x;
212 if (w < 0)
213 w = 0;
214 }
215 if (y + h > s->h) {
216 h = s->h - y;
217 if (h < 0)
218 h = 0;
219 }
220
221 r->x = x; r->y = y; r->w = w; r->h = h;
222 return (w > 0 && h > 0) ? 0 : -1;
223}
224
225DECLSPEC int SDLCALL
226SDL_UpperBlit(SDL_Surface *src, SDL_Rect *srcrect,
227 SDL_Surface *dst, SDL_Rect *dstrect)
228{
229 int sx = 0, sy = 0, sw, sh;
230 int dx = 0, dy = 0;
231 SDL_Rect tmprect = { 0, };
232
233 trace("%p, %p, %p, %p", src, srcrect, dst, dstrect);
234
235 if (src == NULL || dst == NULL)
236 return -1;
237
238 if (srcrect != NULL) {
239 // XXX: dst pos may need to be adjusted in some corner cases
240 if (do_rect_clip(src, srcrect) < 0)
241 return -1;
242 sx = srcrect->x;
243 sy = srcrect->y;
244 sw = srcrect->w;
245 sh = srcrect->h;
246 } else {
247 sw = src->w;
248 sh = src->h;
249 }
250
251 if (dstrect == NULL)
252 dstrect = &tmprect;
253
254 // SDL just uses source w and h
255 dstrect->w = sw;
256 dstrect->h = sh;
257 if (do_rect_clip(dst, dstrect) < 0)
258 return -1;
259 dx = dstrect->x;
260 dy = dstrect->y;
261 sw = dstrect->w;
262 sh = dstrect->h;
263
264 dbg("(%d %d %d %d) -> (%d %d %d %d)", sx, sy, sw, sh, dx, dy, sw, sh);
265
266 if (src->format->BitsPerPixel == dst->format->BitsPerPixel) {
267 int Bpp = src->format->BytesPerPixel;
268 int dpitch = dst->pitch;
269 int spitch = src->pitch;
270 Uint8 *d = (Uint8 *)dst->pixels + dpitch * dy + dx * Bpp;
271 Uint8 *s = (Uint8 *)src->pixels + spitch * sy + sx * Bpp;
272
273 for (sw *= Bpp; sh > 0; d += dpitch, s += spitch, sh--)
274 memcpy(d, s, sw);
275 }
3cb98c5e 276 else
277 not_supported();
0ec348b9 278
279 return 0;
280}
281
282DECLSPEC SDL_Surface * SDLCALL
283SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth,
284 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
285{
286 SDL_Surface *ret;
287
288 trace("%08x, %d, %d, %d, %04x, %04x, %04x, %04x",
289 flags, width, height, depth, Rmask, Gmask, Bmask, Amask);
290
291 ret = alloc_surface(width, height, depth);
292 if (ret == NULL)
293 return NULL;
294
295 ret->pixels = calloc(ret->pitch * height, 1);
296 if (ret->pixels == NULL)
297 goto fail;
298
299 dbg("returning %p", ret);
300 return ret;
301
302fail:
303 free(ret);
304 return NULL;
305}
306
307DECLSPEC int SDLCALL
308SDL_SetColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
309{
310 int i, to;
311
312 trace("%p, %p, %d, %d", surface, colors, firstcolor, ncolors);
313
314 if (surface != g_screen)
315 return 0;
316
317 to = min(ARRAY_SIZE(g_8bpp_pal), firstcolor + ncolors);
318 for (i = firstcolor; i < to; i++) {
319 SDL_Color *c = &colors[i - firstcolor];
320 int r = c->r, g = c->g, b = c->b;
321 // noiz2sa gets a good deal darker that real SDL,
322 // don't know what's going on there
323/*
324 if (r < 0xf8 && (r & 7) > 3) r += 8;
325 if (g < 0xfc && (g & 3) > 1) g += 4;
326 if (b < 0xf8 && (b & 7) > 3) b += 8;
327*/
328 g_8bpp_pal[i] = ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | (b >> 3);
329// g_8bpp_pal[i] += 0x0821;
330 }
331
332 return 0;
333}
334
335DECLSPEC int SDLCALL
336SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
337{
338 trace("%p, %p, %04x", dst, dstrect, color);
339
3cb98c5e 340 if (dst->format->BytesPerPixel != 1) {
341 not_supported();
0ec348b9 342 return -1;
343 }
344 else
345 memset(dst->pixels, color, dst->pitch * dst->h);
346
347 return 0;
348}
349
350/*
351DECLSPEC SDL_Surface * SDLCALL
352SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch,
353 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
354{
355}
356*/
357
358DECLSPEC SDL_RWops * SDLCALL
359SDL_RWFromFile(const char *file, const char *mode)
360{
361 SDL_RWops *ret;
362 FILE *f;
363
364 trace("%s, %s", file, mode);
365
366 f = fopen(file, mode);
367 if (f == NULL)
368 return NULL;
369
370 ret = calloc(1, sizeof(*ret));
371 if (ret == NULL) {
372 fclose(f);
373 return NULL;
374 }
375 ret->hidden.stdio.fp = f;
376
377 return ret;
378}
379
380DECLSPEC void SDLCALL
381SDL_FreeRW(SDL_RWops *area)
382{
383 if (area->hidden.stdio.fp) {
384 fclose(area->hidden.stdio.fp);
385 area->hidden.stdio.fp = NULL;
386 }
387 free(area);
388}
389
390DECLSPEC SDL_Surface * SDLCALL
391SDL_LoadBMP_RW(SDL_RWops *src, int freesrc)
392{
393 struct bmp_dib_v3 {
394 unsigned char magic[2];
395 uint32_t filesz;
396 uint16_t creator1;
397 uint16_t creator2;
398 uint32_t bmp_offset;
399 uint32_t header_sz;
400 int32_t width;
401 int32_t height;
402 uint16_t nplanes;
403 uint16_t bitspp;
404 uint32_t compress_type;
405 uint32_t bmp_bytesz;
406 int32_t hres;
407 int32_t vres;
408 uint32_t ncolors;
409 uint32_t nimpcolors;
410 } __attribute__((packed)) bmp;
411 SDL_Surface *ret = NULL;
412 int data_size, read_size;
3cb98c5e 413 uint8_t *tmp_buf = NULL;
0ec348b9 414 int i, bytespp;
415 FILE *f;
416
417 trace("%p, %d", src, freesrc);
418
419 f = src->hidden.stdio.fp;
420 if (f == NULL)
421 goto out;
422
423 if (fread(&bmp, 1, sizeof(bmp), f) != sizeof(bmp)) {
424 err("bmp read error");
425 goto out;
426 }
427
428 if (bmp.magic[0] != 'B' || bmp.magic[1] != 'M' || bmp.header_sz != 40) {
429 err("unhandled BMP format, sz=%d", bmp.header_sz);
430 goto out;
431 }
432
433 if ((unsigned)bmp.width > 0xffff || (unsigned)bmp.height > 0xffff) {
434 err("BMP size %dx%d out of range", bmp.width, bmp.height);
435 goto out;
436 }
437
438 if (bmp.bitspp != 4) {
439 err("BMP unhandled bpp: %d", bmp.bitspp);
440 goto out;
441 }
442
443 bytespp = bmp.bitspp < 8 ? 1 : (bmp.bitspp + 7) / 8;
444 data_size = bmp.width * bmp.height * bytespp;
445 tmp_buf = malloc(data_size);
446 if (tmp_buf == NULL)
447 goto out;
448
449 if (fseek(f, bmp.bmp_offset, SEEK_SET) != 0) {
450 err("BMP seek error");
451 goto out;
452 }
453
454 read_size = bmp.width * bmp.bitspp / 8;
455 for (i = bmp.height - 1; i > 0; i--) {
456 if (fread((char *)tmp_buf + i * read_size, 1, read_size, f) != read_size) {
457 err("BMP read error");
458 goto out;
459 }
460 }
461
462 if (bmp.bitspp == 4) {
463 // just convert to 8bpp now
464 int c = bmp.width * bmp.height / 2;
465 uint8_t *p = tmp_buf;
466 for (i = c - 1; i >= 0; i--) {
467 p[i * 2 + 1] = p[i] & 0xf;
468 p[i * 2] = p[i] >> 4;
469 }
470 }
471
472 ret = alloc_surface(bmp.width, bmp.height, 8);
473 if (ret == NULL)
474 goto out;
475
476 ret->pixels = tmp_buf;
477 tmp_buf = NULL;
478
479out:
480 if (tmp_buf != NULL)
481 free(tmp_buf);
482 if (freesrc)
483 SDL_FreeRW(src);
484
485 return ret;
486}
487
488DECLSPEC SDL_Surface * SDLCALL
489SDL_ConvertSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags)
490{
491 SDL_Surface *ret;
492 void *data;
493
494 trace("%p, %p, %08x", src, fmt, flags);
495
496 if (src->format->BitsPerPixel != fmt->BitsPerPixel) {
497 err("convert: not implemented");
498 return NULL;
499 }
500
501 data = malloc(src->pitch * src->h);
502 if (data == NULL)
503 return NULL;
504 memcpy(data, src->pixels, src->pitch * src->h);
505
506 ret = alloc_surface(src->w, src->h, fmt->BitsPerPixel);
507 if (ret == NULL) {
508 free(data);
509 return NULL;
510 }
511 ret->pixels = data;
512 return ret;
513}
514
515DECLSPEC int SDLCALL
516SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key)
517{
518 trace("%p, %08x, %04x", surface, flag, key);
519 return 0;
520}
521
0ec348b9 522DECLSPEC void SDLCALL
523SDL_WM_SetCaption(const char *title, const char *icon)
524{
525 trace("%s, %s", title, icon);
526}
527
528DECLSPEC int SDLCALL
529SDL_ShowCursor(int toggle)
530{
531 trace("%d", toggle);
532 return 0;
533}
534
535DECLSPEC char * SDLCALL
536SDL_GetError(void)
537{
538 trace("");
539
540 return "";
541}
542