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