WinRT: fixed a crash in SDL_Quit

SDL was expected that each SDL_DisplayMode had a driverdata field that was SDL_malloc'ed, and was calling SDL_free on them.  This change moves WinRT's driverdata content into a SDL_malloc'ed field.
This commit is contained in:
David Ludwig 2014-03-01 16:08:16 -05:00
parent abfbed92cf
commit f4a5a0fad1
3 changed files with 88 additions and 26 deletions

View File

@ -157,8 +157,15 @@ WINRT_ProcessWindowSizeChange()
// window-resize event as it appeared the SDL window didn't change // window-resize event as it appeared the SDL window didn't change
// size, and the Direct3D 11.1 renderer wouldn't resize its swap // size, and the Direct3D 11.1 renderer wouldn't resize its swap
// chain. // chain.
SDL_DisplayMode resizedDisplayMode = WINRT_CalcDisplayModeUsingNativeWindow(); SDL_DisplayMode resizedDisplayMode;
if (WINRT_CalcDisplayModeUsingNativeWindow(&resizedDisplayMode) != 0) {
return;
}
if (resizedDisplayMode.w == 0 || resizedDisplayMode.h == 0) { if (resizedDisplayMode.w == 0 || resizedDisplayMode.h == 0) {
if (resizedDisplayMode.driverdata) {
SDL_free(resizedDisplayMode.driverdata);
}
return; return;
} }
@ -166,8 +173,14 @@ WINRT_ProcessWindowSizeChange()
SDL_zero(oldDisplayMode); SDL_zero(oldDisplayMode);
if (WINRT_GlobalSDLVideoDevice) { if (WINRT_GlobalSDLVideoDevice) {
oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode; oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode;
if (WINRT_DuplicateDisplayMode(&(WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode), &resizedDisplayMode) != 0) {
SDL_free(resizedDisplayMode.driverdata);
return;
}
WINRT_GlobalSDLVideoDevice->displays[0].current_mode = resizedDisplayMode; WINRT_GlobalSDLVideoDevice->displays[0].current_mode = resizedDisplayMode;
WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = resizedDisplayMode; if (WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata) {
SDL_free(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata);
}
WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0] = resizedDisplayMode; WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0] = resizedDisplayMode;
} }
@ -184,8 +197,8 @@ WINRT_ProcessWindowSizeChange()
// Landscape to LandscapeFlipped, Portrait to PortraitFlipped, // Landscape to LandscapeFlipped, Portrait to PortraitFlipped,
// or vice-versa on either of those two, lead to the Direct3D renderer // or vice-versa on either of those two, lead to the Direct3D renderer
// getting updated. // getting updated.
const DisplayOrientations oldOrientation = (DisplayOrientations) (unsigned int) oldDisplayMode.driverdata; const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
const DisplayOrientations newOrientation = (DisplayOrientations) (unsigned int) resizedDisplayMode.driverdata; const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)resizedDisplayMode.driverdata)->currentOrientation;
if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) || if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) ||
(oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) || (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) ||
@ -212,6 +225,10 @@ WINRT_ProcessWindowSizeChange()
} }
#endif #endif
} }
if (oldDisplayMode.driverdata) {
SDL_free(oldDisplayMode.driverdata);
}
} }
SDL_WinRTApp::SDL_WinRTApp() : SDL_WinRTApp::SDL_WinRTApp() :

View File

@ -147,33 +147,42 @@ WINRT_VideoInit(_THIS)
return 0; return 0;
} }
SDL_DisplayMode int
WINRT_CalcDisplayModeUsingNativeWindow() WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode)
{ {
SDL_DisplayModeData * driverdata;
using namespace Windows::Graphics::Display; using namespace Windows::Graphics::Display;
// Create an empty, zeroed-out display mode: // Initialize the mode to all zeros:
SDL_DisplayMode mode; SDL_zerop(mode);
SDL_zero(mode);
// Go no further if a native window cannot be accessed. This can happen, // Go no further if a native window cannot be accessed. This can happen,
// for example, if this function is called from certain threads, such as // for example, if this function is called from certain threads, such as
// the SDL/XAML thread. // the SDL/XAML thread.
if (!CoreWindow::GetForCurrentThread()) { if (!CoreWindow::GetForCurrentThread()) {
return mode; return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread");
} }
// Create a driverdata field:
driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
if (!driverdata) {
return SDL_OutOfMemory();
}
SDL_zerop(driverdata);
// Fill in most fields: // Fill in most fields:
mode.format = SDL_PIXELFORMAT_RGB888; mode->format = SDL_PIXELFORMAT_RGB888;
mode.refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps) mode->refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
mode.driverdata = (void *) DisplayProperties::CurrentOrientation; mode->driverdata = driverdata;
driverdata->currentOrientation = DisplayProperties::CurrentOrientation;
// Calculate the display size given the window size, taking into account // Calculate the display size given the window size, taking into account
// the current display's DPI: // the current display's DPI:
const float currentDPI = Windows::Graphics::Display::DisplayProperties::LogicalDpi; const float currentDPI = Windows::Graphics::Display::DisplayProperties::LogicalDpi;
const float dipsPerInch = 96.0f; const float dipsPerInch = 96.0f;
mode.w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch); mode->w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch);
mode.h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch); mode->h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch);
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
// On Windows Phone, the native window's size is always in portrait, // On Windows Phone, the native window's size is always in portrait,
@ -186,32 +195,52 @@ WINRT_CalcDisplayModeUsingNativeWindow()
case DisplayOrientations::Landscape: case DisplayOrientations::Landscape:
case DisplayOrientations::LandscapeFlipped: case DisplayOrientations::LandscapeFlipped:
{ {
const int tmp = mode.h; const int tmp = mode->h;
mode.h = mode.w; mode->h = mode->w;
mode.w = tmp; mode->w = tmp;
break; break;
} }
default: default:
break; break;
} }
// Attach the mode to te
#endif #endif
return mode; return 0;
}
int
WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src)
{
SDL_DisplayModeData * driverdata;
driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
if (!driverdata) {
return SDL_OutOfMemory();
}
SDL_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData));
SDL_memcpy(dest, src, sizeof(SDL_DisplayMode));
dest->driverdata = driverdata;
return 0;
} }
int int
WINRT_InitModes(_THIS) WINRT_InitModes(_THIS)
{ {
// Retrieve the display mode: // Retrieve the display mode:
SDL_DisplayMode mode = WINRT_CalcDisplayModeUsingNativeWindow(); SDL_DisplayMode mode, desktop_mode;
if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) {
return -1; // If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error
}
if (mode.w == 0 || mode.h == 0) { if (mode.w == 0 || mode.h == 0) {
SDL_free(mode.driverdata);
return SDL_SetError("Unable to calculate the WinRT window/display's size"); return SDL_SetError("Unable to calculate the WinRT window/display's size");
} }
if (SDL_AddBasicVideoDisplay(&mode) < 0) { if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) {
return -1;
}
if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) {
return -1; return -1;
} }

View File

@ -44,9 +44,25 @@ extern SDL_Window * WINRT_GlobalSDLWindow;
/* The global, WinRT, video device. */ /* The global, WinRT, video device. */
extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice; extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice;
/* Computes the current display mode for Plain Direct3D (non-XAML) apps */ /* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings.
extern SDL_DisplayMode WINRT_CalcDisplayModeUsingNativeWindow();
Pass in an allocated SDL_DisplayMode field to store the data in.
This function will return 0 on success, -1 on failure.
If this function succeeds, be sure to call SDL_free on the
SDL_DisplayMode's driverdata field.
*/
extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode);
/* Duplicates a display mode, copying over driverdata as necessary */
extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src);
/* Display mode internals */
typedef struct
{
Windows::Graphics::Display::DisplayOrientations currentOrientation;
} SDL_DisplayModeData;
#ifdef __cplusplus_winrt #ifdef __cplusplus_winrt