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