src/video/bwindow/SDL_bmodes.cc
author Nathan Heisey <nathanheisey@gmail.com>
Tue, 26 Jul 2011 10:13:34 +0000
changeset 5926 d9d57de9fb4e
parent 5925 262ce29aabf6
child 5927 463b84c19645
permissions -rw-r--r--
Fixed seg fault on video quit
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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 
    22 
    23 
    24 #include <AppKit.h>
    25 #include <InterfaceKit.h>
    26 #include "SDL_bmodes.h"
    27 #include "SDL_BWin.h"
    28 
    29 #include "../../main/beos/SDL_BApp.h"
    30 
    31 #ifdef __cplusplus
    32 extern "C" {
    33 #endif
    34 
    35 /* This wrapper is here so that the driverdata can be freed */
    36 typedef struct SDL_DisplayModeData {
    37 	display_mode *bmode;
    38 };
    39 
    40 
    41 
    42 static inline SDL_BWin *_ToBeWin(SDL_Window *window) {
    43 	return ((SDL_BWin*)(window->driverdata));
    44 }
    45 
    46 static inline SDL_BApp *_GetBeApp() {
    47 	return ((SDL_BApp*)be_app);
    48 }
    49 
    50 
    51 /* Copied from haiku/trunk/src/preferences/screen/ScreenMode.cpp */
    52 static float get_refresh_rate(display_mode &mode) {
    53 	return float(mode.timing.pixel_clock * 1000)
    54 		/ float(mode.timing.h_total * mode.timing.v_total);
    55 }
    56 
    57 static inline int ColorSpaceToBitsPerPixel(uint32 colorspace)
    58 {
    59 	int bitsperpixel;
    60 
    61 	bitsperpixel = 0;
    62 	switch (colorspace) {
    63 	    case B_CMAP8:
    64 		bitsperpixel = 8;
    65 		break;
    66 	    case B_RGB15:
    67 	    case B_RGBA15:
    68 	    case B_RGB15_BIG:
    69 	    case B_RGBA15_BIG:
    70 		bitsperpixel = 15;
    71 		break;
    72 	    case B_RGB16:
    73 	    case B_RGB16_BIG:
    74 		bitsperpixel = 16;
    75 		break;
    76 	    case B_RGB32:
    77 	    case B_RGBA32:
    78 	    case B_RGB32_BIG:
    79 	    case B_RGBA32_BIG:
    80 		bitsperpixel = 32;
    81 		break;
    82 	    default:
    83 		break;
    84 	}
    85 	return(bitsperpixel);
    86 }
    87 
    88 static inline int32 BPPToSDLPxFormat(int32 bpp) {
    89 	/* Translation taken from SDL_windowsmodes.c */
    90 	switch (bpp) {
    91 	case 32:
    92 		return SDL_PIXELFORMAT_RGB888;
    93 		break;
    94 	case 24:	/* May not be supported by Haiku */
    95 		return SDL_PIXELFORMAT_RGB24;
    96 		break;
    97 	case 16:
    98 		return SDL_PIXELFORMAT_RGB565;
    99 		break;
   100 	case 15:
   101 		return SDL_PIXELFORMAT_RGB555;
   102 		break;
   103 	case 8:
   104 		return SDL_PIXELFORMAT_INDEX8;
   105 		break;
   106 	case 4:		/* May not be supported by Haiku */
   107 		return SDL_PIXELFORMAT_INDEX4LSB;
   108 		break;
   109 	}
   110 }
   111 
   112 static inline void BE_BDisplayModeToSdlDisplayMode(display_mode *bmode,
   113 		SDL_DisplayMode *mode) {
   114 	mode->w = bmode->virtual_width;
   115 	mode->h = bmode->virtual_height;
   116 	mode->refresh_rate = (int)get_refresh_rate(*bmode);
   117 	SDL_DisplayModeData *data = (SDL_DisplayModeData*)SDL_calloc(1, sizeof(SDL_DisplayModeData));
   118 	data->bmode = bmode;
   119 	mode->driverdata = data;
   120 
   121 	/* Set the format */
   122 	int32 bpp = ColorSpaceToBitsPerPixel(bmode->space);
   123 	mode->format = BPPToSDLPxFormat(bpp);
   124 }
   125 
   126 /* Later, there may be more than one monitor available */
   127 void BE_AddDisplay(BScreen *screen) {
   128 	SDL_VideoDisplay display;
   129 	SDL_DisplayMode *mode = (SDL_DisplayMode*)SDL_calloc(1, sizeof(SDL_DisplayMode));
   130 	display_mode bmode;
   131 	screen->GetMode(&bmode);
   132 
   133 	BE_BDisplayModeToSdlDisplayMode(&bmode, mode);
   134 	
   135 	SDL_zero(display);
   136 	display.desktop_mode = *mode;
   137 	display.current_mode = *mode;
   138 	SDL_AddVideoDisplay(&display);
   139 }
   140 
   141 int BE_InitModes(_THIS) {
   142 	BScreen screen;
   143 	
   144 	/* Save the current display mode */
   145 	display_mode *prevMode;
   146 	screen.GetMode(prevMode);
   147 	_GetBeApp()->SetPrevMode(prevMode);
   148 
   149 	/* Only one possible video display right now */
   150 	BE_AddDisplay(&screen);
   151 }
   152 
   153 int BE_QuitModes(_THIS) {
   154 	printf(__FILE__": %d; Begin quit\n", __LINE__);
   155 	/* Restore the previous video mode */
   156 	BScreen screen;
   157 	display_mode *savedMode = _GetBeApp()->GetPrevMode();
   158 	screen.SetMode(savedMode);
   159 	return 0;
   160 }
   161 
   162 
   163 int BE_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect) {
   164 	BScreen bscreen;
   165 	BRect rc = bscreen.Frame();
   166 	rect->x = (int)rc.left;
   167 	rect->y = (int)rc.top;
   168 	rect->w = (int)rc.Width() + 1;
   169 	rect->h = (int)rc.Height() + 1;
   170 	return 0;
   171 }
   172 
   173 void BE_GetDisplayModes(_THIS, SDL_VideoDisplay *display) {
   174 	/* Get the current screen */
   175 	BScreen bscreen;
   176 
   177 	/* Iterate through all of the modes */
   178 	SDL_DisplayMode mode;
   179 	display_mode this_bmode;
   180 	display_mode *bmodes;
   181 	uint32 count, i;
   182 	
   183 	/* Get graphics-hardware supported modes */
   184 	bscreen.GetModeList(&bmodes, &count);
   185 	bscreen.GetMode(&this_bmode);
   186 	
   187 	for(i = 0; i < count; ++i) {
   188 		//FIXME: Apparently there are errors with colorspace changes
   189 		if (bmodes[i].space == this_bmode.space) {
   190 			BE_BDisplayModeToSdlDisplayMode(&bmodes[i], &mode);
   191 			SDL_AddDisplayMode(display, &mode);
   192 		}
   193 	}
   194 	free(bmodes);
   195 }
   196 
   197 int BE_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode){
   198 	/* Get the current screen */
   199 	BScreen bscreen;
   200 	
   201 	/* Set the mode using the driver data */
   202 	display_mode *bmode = ((SDL_DisplayModeData*)mode->driverdata)->bmode;
   203 	if(bscreen.SetMode(bmode) == B_OK) {
   204 		return 0;	/* No error */
   205 	}
   206 	
   207 	return -1;
   208 }
   209 
   210 
   211 
   212 int BE_CreateWindowFramebuffer(_THIS, SDL_Window * window,
   213                                        Uint32 * format,
   214                                        void ** pixels, int *pitch) {
   215 	SDL_BWin *bwin = _ToBeWin(window);
   216 	BScreen bscreen;
   217 	if(!bscreen.IsValid()) {
   218 		return -1;
   219 	}
   220 	
   221 	while(!bwin->Connected()) { snooze(10); }
   222 
   223 	/* Make sure we have exclusive access to frame buffer data */
   224 	bwin->LockBuffer();
   225 
   226 	/* format */
   227 	display_mode bmode;
   228 	bscreen.GetMode(&bmode);
   229 	int32 bpp = ColorSpaceToBitsPerPixel(bmode.space);
   230 	*format = BPPToSDLPxFormat(bpp);
   231 
   232 	/* pitch = width of screen, in bytes */
   233 	*pitch = bwin->GetFbWidth() * bwin->GetBytesPerPx();
   234 
   235 	/* Create a copy of the pixel buffer if it doesn't recycle */
   236 	*pixels = bwin->GetWindowFramebuffer();
   237 	if( bwin->CanTrashWindowBuffer() || (*pixels) == NULL) {
   238 		if( (*pixels) != NULL ) {
   239 			SDL_free(*pixels);
   240 		}
   241 		*pixels = SDL_calloc((*pitch) * bwin->GetFbHeight() * 
   242 			bwin->GetBytesPerPx(), sizeof(uint8));
   243 		bwin->SetWindowFramebuffer((uint8*)(*pixels));
   244 	}
   245 
   246 	bwin->UnlockBuffer();
   247 	return 0;
   248 }
   249 
   250 
   251 
   252 int BE_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
   253                                       SDL_Rect * rects, int numrects) {
   254 	SDL_BWin *bwin = _ToBeWin(window);
   255 	BScreen bscreen;
   256 	if(!bscreen.IsValid()) {
   257 		return -1;
   258 	}
   259 
   260 	if(bwin->ConnectionEnabled() && bwin->Connected()) {
   261 		bwin->LockBuffer();
   262 		int32 windowPitch = window->surface->pitch;
   263 		int32 bufferPitch = bwin->GetRowBytes();
   264 		uint8 *windowpx;
   265 		uint8 *bufferpx;
   266 
   267 		int32 BPP = bwin->GetBytesPerPx();
   268 		uint8 *windowBaseAddress = (uint8*)window->surface->pixels;
   269 		int32 windowSub = bwin->GetFbX() * BPP +
   270 						  bwin->GetFbY() * windowPitch;
   271 		clipping_rect *clips = bwin->GetClips();
   272 		int32 numClips = bwin->GetNumClips();
   273 		int i, y;
   274 
   275 		/* Blit each clipping rectangle */
   276 		bscreen.WaitForRetrace();
   277 		for(i = 0; i < numClips; ++i) {
   278 			clipping_rect rc = clips[i];
   279 			/* Get addresses of the start of each clipping rectangle */
   280 			int32 width = clips[i].right - clips[i].left + 1;
   281 			int32 height = clips[i].bottom - clips[i].top + 1;
   282 			bufferpx = bwin->GetBufferPx() + 
   283 				clips[i].top * bufferPitch + clips[i].left * BPP;
   284 			windowpx = windowBaseAddress + 
   285 				clips[i].top * windowPitch + clips[i].left * BPP - windowSub;
   286 
   287 			/* Copy each row of pixels from the window buffer into the frame
   288 			   buffer */
   289 			for(y = 0; y < height; ++y)
   290 			{
   291 				memcpy(bufferpx, windowpx, width * BPP);
   292 				bufferpx += bufferPitch;
   293 				windowpx += windowPitch;
   294 			}
   295 		}
   296 		bwin->UnlockBuffer();
   297 	}
   298 	return 0;
   299 }
   300 
   301 void BE_DestroyWindowFramebuffer(_THIS, SDL_Window * window) {
   302 	SDL_BWin *bwin = _ToBeWin(window);
   303 	
   304 	bwin->LockBuffer();
   305 	
   306 	/* Free and clear the window buffer */
   307 	uint8* winBuffer = bwin->GetWindowFramebuffer();
   308 	SDL_free(winBuffer);
   309 	bwin->SetWindowFramebuffer(NULL);
   310 	bwin->UnlockBuffer();
   311 }
   312 
   313 #ifdef __cplusplus
   314 }
   315 #endif