1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_HAIKU
24 
25 #include <AppKit.h>
26 #include <InterfaceKit.h>
27 #include "SDL_bmodes.h"
28 #include "SDL_BWin.h"
29 
30 #if SDL_VIDEO_OPENGL
31 #include "SDL_bopengl.h"
32 #endif
33 
34 #include "../../main/haiku/SDL_BApp.h"
35 
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39 
40 
41 #define WRAP_BMODE 1 /* FIXME: Some debate as to whether this is necessary */
42 
43 #if WRAP_BMODE
44 /* This wrapper is here so that the driverdata can be freed without freeing
45    the display_mode structure */
46 struct SDL_DisplayModeData {
47     display_mode *bmode;
48 };
49 #endif
50 
_ToBeWin(SDL_Window * window)51 static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) {
52     return ((SDL_BWin*)(window->driverdata));
53 }
54 
_GetBeApp()55 static SDL_INLINE SDL_BApp *_GetBeApp() {
56     return ((SDL_BApp*)be_app);
57 }
58 
_ExtractBMode(SDL_DisplayMode * mode)59 static SDL_INLINE display_mode * _ExtractBMode(SDL_DisplayMode *mode) {
60 #if WRAP_BMODE
61     return ((SDL_DisplayModeData*)mode->driverdata)->bmode;
62 #else
63     return (display_mode*)(mode->driverdata);
64 #endif
65 }
66 
67 /* Copied from haiku/trunk/src/preferences/screen/ScreenMode.cpp */
get_refresh_rate(display_mode & mode)68 static float get_refresh_rate(display_mode &mode) {
69     return float(mode.timing.pixel_clock * 1000)
70         / float(mode.timing.h_total * mode.timing.v_total);
71 }
72 
73 
74 #if 0
75 /* TODO:
76  * This is a useful debugging tool.  Uncomment and insert into code as needed.
77  */
78 void _SpoutModeData(display_mode *bmode) {
79     printf("BMode:\n");
80     printf("\tw,h = (%i,%i)\n", bmode->virtual_width, bmode->virtual_height);
81     printf("\th,v = (%i,%i)\n", bmode->h_display_start,
82             bmode->v_display_start);
83     if(bmode->flags) {
84         printf("\tFlags:\n");
85         if(bmode->flags & B_SCROLL) {
86             printf("\t\tB_SCROLL\n");
87         }
88         if(bmode->flags & B_8_BIT_DAC) {
89             printf("\t\tB_8_BIT_DAC\n");
90         }
91         if(bmode->flags & B_HARDWARE_CURSOR) {
92             printf("\t\tB_HARDWARE_CURSOR\n");
93         }
94         if(bmode->flags & B_PARALLEL_ACCESS) {
95             printf("\t\tB_PARALLEL_ACCESS\n");
96         }
97         if(bmode->flags & B_DPMS) {
98             printf("\t\tB_DPMS\n");
99         }
100         if(bmode->flags & B_IO_FB_NA) {
101             printf("\t\tB_IO_FB_NA\n");
102         }
103     }
104     printf("\tTiming:\n");
105     printf("\t\tpx clock: %i\n", bmode->timing.pixel_clock);
106     printf("\t\th - display: %i sync start: %i sync end: %i total: %i\n",
107         bmode->timing.h_display, bmode->timing.h_sync_start,
108         bmode->timing.h_sync_end, bmode->timing.h_total);
109     printf("\t\tv - display: %i sync start: %i sync end: %i total: %i\n",
110         bmode->timing.v_display, bmode->timing.v_sync_start,
111         bmode->timing.v_sync_end, bmode->timing.v_total);
112     if(bmode->timing.flags) {
113         printf("\t\tFlags:\n");
114         if(bmode->timing.flags & B_BLANK_PEDESTAL) {
115             printf("\t\t\tB_BLANK_PEDESTAL\n");
116         }
117         if(bmode->timing.flags & B_TIMING_INTERLACED) {
118             printf("\t\t\tB_TIMING_INTERLACED\n");
119         }
120         if(bmode->timing.flags & B_POSITIVE_HSYNC) {
121             printf("\t\t\tB_POSITIVE_HSYNC\n");
122         }
123         if(bmode->timing.flags & B_POSITIVE_VSYNC) {
124             printf("\t\t\tB_POSITIVE_VSYNC\n");
125         }
126         if(bmode->timing.flags & B_SYNC_ON_GREEN) {
127             printf("\t\t\tB_SYNC_ON_GREEN\n");
128         }
129     }
130 }
131 #endif
132 
133 
134 
HAIKU_ColorSpaceToBitsPerPixel(uint32 colorspace)135 int32 HAIKU_ColorSpaceToBitsPerPixel(uint32 colorspace)
136 {
137     int bitsperpixel;
138 
139     bitsperpixel = 0;
140     switch (colorspace) {
141         case B_CMAP8:
142         bitsperpixel = 8;
143         break;
144         case B_RGB15:
145         case B_RGBA15:
146         case B_RGB15_BIG:
147         case B_RGBA15_BIG:
148         bitsperpixel = 15;
149         break;
150         case B_RGB16:
151         case B_RGB16_BIG:
152         bitsperpixel = 16;
153         break;
154         case B_RGB32:
155         case B_RGBA32:
156         case B_RGB32_BIG:
157         case B_RGBA32_BIG:
158         bitsperpixel = 32;
159         break;
160         default:
161         break;
162     }
163     return(bitsperpixel);
164 }
165 
HAIKU_BPPToSDLPxFormat(int32 bpp)166 int32 HAIKU_BPPToSDLPxFormat(int32 bpp) {
167     /* Translation taken from SDL_windowsmodes.c */
168     switch (bpp) {
169     case 32:
170         return SDL_PIXELFORMAT_RGB888;
171         break;
172     case 24:    /* May not be supported by Haiku */
173         return SDL_PIXELFORMAT_RGB24;
174         break;
175     case 16:
176         return SDL_PIXELFORMAT_RGB565;
177         break;
178     case 15:
179         return SDL_PIXELFORMAT_RGB555;
180         break;
181     case 8:
182         return SDL_PIXELFORMAT_INDEX8;
183         break;
184     case 4:        /* May not be supported by Haiku */
185         return SDL_PIXELFORMAT_INDEX4LSB;
186         break;
187     }
188 
189     /* May never get here, but safer and needed to shut up compiler */
190     SDL_SetError("Invalid bpp value");
191     return 0;
192 }
193 
_BDisplayModeToSdlDisplayMode(display_mode * bmode,SDL_DisplayMode * mode)194 static void _BDisplayModeToSdlDisplayMode(display_mode *bmode,
195         SDL_DisplayMode *mode) {
196     mode->w = bmode->virtual_width;
197     mode->h = bmode->virtual_height;
198     mode->refresh_rate = (int)get_refresh_rate(*bmode);
199 
200 #if WRAP_BMODE
201     SDL_DisplayModeData *data = (SDL_DisplayModeData*)SDL_calloc(1,
202         sizeof(SDL_DisplayModeData));
203     data->bmode = bmode;
204 
205     mode->driverdata = data;
206 
207 #else
208 
209     mode->driverdata = bmode;
210 #endif
211 
212     /* Set the format */
213     int32 bpp = HAIKU_ColorSpaceToBitsPerPixel(bmode->space);
214     mode->format = HAIKU_BPPToSDLPxFormat(bpp);
215 }
216 
217 /* Later, there may be more than one monitor available */
_AddDisplay(BScreen * screen)218 static void _AddDisplay(BScreen *screen) {
219     SDL_VideoDisplay display;
220     SDL_DisplayMode *mode = (SDL_DisplayMode*)SDL_calloc(1,
221         sizeof(SDL_DisplayMode));
222     display_mode *bmode = (display_mode*)SDL_calloc(1, sizeof(display_mode));
223     screen->GetMode(bmode);
224 
225     _BDisplayModeToSdlDisplayMode(bmode, mode);
226 
227     SDL_zero(display);
228     display.desktop_mode = *mode;
229     display.current_mode = *mode;
230 
231     SDL_AddVideoDisplay(&display);
232 }
233 
234 /*
235  * Functions called by SDL
236  */
237 
HAIKU_InitModes(_THIS)238 int HAIKU_InitModes(_THIS) {
239     BScreen screen;
240 
241     /* TODO: When Haiku supports multiple display screens, call
242        _AddDisplayScreen() for each of them. */
243     _AddDisplay(&screen);
244     return 0;
245 }
246 
HAIKU_QuitModes(_THIS)247 int HAIKU_QuitModes(_THIS) {
248     /* FIXME: Nothing really needs to be done here at the moment? */
249     return 0;
250 }
251 
252 
HAIKU_GetDisplayBounds(_THIS,SDL_VideoDisplay * display,SDL_Rect * rect)253 int HAIKU_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect) {
254     BScreen bscreen;
255     BRect rc = bscreen.Frame();
256     rect->x = (int)rc.left;
257     rect->y = (int)rc.top;
258     rect->w = (int)rc.Width() + 1;
259     rect->h = (int)rc.Height() + 1;
260     return 0;
261 }
262 
HAIKU_GetDisplayModes(_THIS,SDL_VideoDisplay * display)263 void HAIKU_GetDisplayModes(_THIS, SDL_VideoDisplay *display) {
264     /* Get the current screen */
265     BScreen bscreen;
266 
267     /* Iterate through all of the modes */
268     SDL_DisplayMode mode;
269     display_mode this_bmode;
270     display_mode *bmodes;
271     uint32 count, i;
272 
273     /* Get graphics-hardware supported modes */
274     bscreen.GetModeList(&bmodes, &count);
275     bscreen.GetMode(&this_bmode);
276 
277     for(i = 0; i < count; ++i) {
278         // FIXME: Apparently there are errors with colorspace changes
279         if (bmodes[i].space == this_bmode.space) {
280             _BDisplayModeToSdlDisplayMode(&bmodes[i], &mode);
281             SDL_AddDisplayMode(display, &mode);
282         }
283     }
284     free(bmodes);
285 }
286 
287 
HAIKU_SetDisplayMode(_THIS,SDL_VideoDisplay * display,SDL_DisplayMode * mode)288 int HAIKU_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode){
289     /* Get the current screen */
290     BScreen bscreen;
291     if(!bscreen.IsValid()) {
292         printf(__FILE__": %d - ERROR: BAD SCREEN\n", __LINE__);
293     }
294 
295     /* Set the mode using the driver data */
296     display_mode *bmode = _ExtractBMode(mode);
297 
298 
299     /* FIXME: Is the first option always going to be the right one? */
300     uint32 c = 0, i;
301     display_mode *bmode_list;
302     bscreen.GetModeList(&bmode_list, &c);
303     for(i = 0; i < c; ++i) {
304         if(    bmode_list[i].space == bmode->space &&
305             bmode_list[i].virtual_width == bmode->virtual_width &&
306             bmode_list[i].virtual_height == bmode->virtual_height ) {
307                 bmode = &bmode_list[i];
308                 break;
309         }
310     }
311 
312     if(bscreen.SetMode(bmode) != B_OK) {
313         return SDL_SetError("Bad video mode");
314     }
315 
316     free(bmode_list);
317 
318 #if SDL_VIDEO_OPENGL
319     /* FIXME: Is there some way to reboot the OpenGL context?  This doesn't
320        help */
321 //    HAIKU_GL_RebootContexts(_this);
322 #endif
323 
324     return 0;
325 }
326 
327 #ifdef __cplusplus
328 }
329 #endif
330 
331 #endif /* SDL_VIDEO_DRIVER_HAIKU */
332 
333 /* vi: set ts=4 sw=4 expandtab: */
334