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