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