WinRT: fixed a crash in SDL_Quit
authorDavid Ludwig <dludwig@pobox.com>
Sat, 01 Mar 2014 16:08:16 -0500
changeset 85786517b6aca713
parent 8577 462760a8b82e
child 8579 ee7126c459d0
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.
src/core/winrt/SDL_winrtapp_direct3d.cpp
src/video/winrt/SDL_winrtvideo.cpp
src/video/winrt/SDL_winrtvideo_cpp.h
     1.1 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp	Sun Jan 26 08:06:36 2014 -0500
     1.2 +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp	Sat Mar 01 16:08:16 2014 -0500
     1.3 @@ -157,8 +157,15 @@
     1.4      // window-resize event as it appeared the SDL window didn't change
     1.5      // size, and the Direct3D 11.1 renderer wouldn't resize its swap
     1.6      // chain.
     1.7 -    SDL_DisplayMode resizedDisplayMode = WINRT_CalcDisplayModeUsingNativeWindow();
     1.8 +    SDL_DisplayMode resizedDisplayMode;
     1.9 +    if (WINRT_CalcDisplayModeUsingNativeWindow(&resizedDisplayMode) != 0) {
    1.10 +        return;
    1.11 +    }
    1.12 +    
    1.13      if (resizedDisplayMode.w == 0 || resizedDisplayMode.h == 0) {
    1.14 +        if (resizedDisplayMode.driverdata) {
    1.15 +            SDL_free(resizedDisplayMode.driverdata);
    1.16 +        }
    1.17          return;
    1.18      }
    1.19  
    1.20 @@ -166,8 +173,14 @@
    1.21      SDL_zero(oldDisplayMode);
    1.22      if (WINRT_GlobalSDLVideoDevice) {
    1.23          oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode;
    1.24 +        if (WINRT_DuplicateDisplayMode(&(WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode), &resizedDisplayMode) != 0) {
    1.25 +            SDL_free(resizedDisplayMode.driverdata);
    1.26 +            return;
    1.27 +        }
    1.28          WINRT_GlobalSDLVideoDevice->displays[0].current_mode = resizedDisplayMode;
    1.29 -        WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = resizedDisplayMode;
    1.30 +        if (WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata) {
    1.31 +            SDL_free(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata);
    1.32 +        }
    1.33          WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0] = resizedDisplayMode;
    1.34      }
    1.35  
    1.36 @@ -184,8 +197,8 @@
    1.37          // Landscape to LandscapeFlipped, Portrait to PortraitFlipped,
    1.38          // or vice-versa on either of those two, lead to the Direct3D renderer
    1.39          // getting updated.
    1.40 -        const DisplayOrientations oldOrientation = (DisplayOrientations) (unsigned int) oldDisplayMode.driverdata;
    1.41 -        const DisplayOrientations newOrientation = (DisplayOrientations) (unsigned int) resizedDisplayMode.driverdata;
    1.42 +        const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
    1.43 +        const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)resizedDisplayMode.driverdata)->currentOrientation;
    1.44  
    1.45          if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) ||
    1.46              (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) ||
    1.47 @@ -212,6 +225,10 @@
    1.48          }
    1.49  #endif
    1.50      }
    1.51 +    
    1.52 +    if (oldDisplayMode.driverdata) {
    1.53 +        SDL_free(oldDisplayMode.driverdata);
    1.54 +    }
    1.55  }
    1.56  
    1.57  SDL_WinRTApp::SDL_WinRTApp() :
     2.1 --- a/src/video/winrt/SDL_winrtvideo.cpp	Sun Jan 26 08:06:36 2014 -0500
     2.2 +++ b/src/video/winrt/SDL_winrtvideo.cpp	Sat Mar 01 16:08:16 2014 -0500
     2.3 @@ -147,33 +147,42 @@
     2.4      return 0;
     2.5  }
     2.6  
     2.7 -SDL_DisplayMode
     2.8 -WINRT_CalcDisplayModeUsingNativeWindow()
     2.9 +int
    2.10 +WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode)
    2.11  {
    2.12 +    SDL_DisplayModeData * driverdata;
    2.13 +
    2.14      using namespace Windows::Graphics::Display;
    2.15  
    2.16 -    // Create an empty, zeroed-out display mode:
    2.17 -    SDL_DisplayMode mode;
    2.18 -    SDL_zero(mode);
    2.19 +    // Initialize the mode to all zeros:
    2.20 +    SDL_zerop(mode);
    2.21  
    2.22      // Go no further if a native window cannot be accessed.  This can happen,
    2.23      // for example, if this function is called from certain threads, such as
    2.24      // the SDL/XAML thread.
    2.25      if (!CoreWindow::GetForCurrentThread()) {
    2.26 -        return mode;
    2.27 +        return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread");
    2.28      }
    2.29  
    2.30 +    // Create a driverdata field:
    2.31 +    driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
    2.32 +    if (!driverdata) {
    2.33 +        return SDL_OutOfMemory();
    2.34 +    }
    2.35 +    SDL_zerop(driverdata);
    2.36 +
    2.37      // Fill in most fields:
    2.38 -    mode.format = SDL_PIXELFORMAT_RGB888;
    2.39 -    mode.refresh_rate = 0;  // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
    2.40 -    mode.driverdata = (void *) DisplayProperties::CurrentOrientation;
    2.41 +    mode->format = SDL_PIXELFORMAT_RGB888;
    2.42 +    mode->refresh_rate = 0;  // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
    2.43 +    mode->driverdata = driverdata;
    2.44 +    driverdata->currentOrientation = DisplayProperties::CurrentOrientation;
    2.45  
    2.46      // Calculate the display size given the window size, taking into account
    2.47      // the current display's DPI:
    2.48      const float currentDPI = Windows::Graphics::Display::DisplayProperties::LogicalDpi; 
    2.49      const float dipsPerInch = 96.0f;
    2.50 -    mode.w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch);
    2.51 -    mode.h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch);
    2.52 +    mode->w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch);
    2.53 +    mode->h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch);
    2.54  
    2.55  #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
    2.56      // On Windows Phone, the native window's size is always in portrait,
    2.57 @@ -186,32 +195,52 @@
    2.58          case DisplayOrientations::Landscape:
    2.59          case DisplayOrientations::LandscapeFlipped:
    2.60          {
    2.61 -            const int tmp = mode.h;
    2.62 -            mode.h = mode.w;
    2.63 -            mode.w = tmp;
    2.64 +            const int tmp = mode->h;
    2.65 +            mode->h = mode->w;
    2.66 +            mode->w = tmp;
    2.67              break;
    2.68          }
    2.69  
    2.70          default:
    2.71              break;
    2.72      }
    2.73 -
    2.74 -    // Attach the mode to te
    2.75  #endif
    2.76  
    2.77 -    return mode;
    2.78 +    return 0;
    2.79 +}
    2.80 +
    2.81 +int
    2.82 +WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src)
    2.83 +{
    2.84 +    SDL_DisplayModeData * driverdata;
    2.85 +    driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
    2.86 +    if (!driverdata) {
    2.87 +        return SDL_OutOfMemory();
    2.88 +    }
    2.89 +    SDL_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData));
    2.90 +    SDL_memcpy(dest, src, sizeof(SDL_DisplayMode));
    2.91 +    dest->driverdata = driverdata;
    2.92 +    return 0;
    2.93  }
    2.94  
    2.95  int
    2.96  WINRT_InitModes(_THIS)
    2.97  {
    2.98      // Retrieve the display mode:
    2.99 -    SDL_DisplayMode mode = WINRT_CalcDisplayModeUsingNativeWindow();
   2.100 +    SDL_DisplayMode mode, desktop_mode;
   2.101 +    if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) {
   2.102 +        return -1;	// If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error
   2.103 +    }
   2.104 +    
   2.105      if (mode.w == 0 || mode.h == 0) {
   2.106 +        SDL_free(mode.driverdata);
   2.107          return SDL_SetError("Unable to calculate the WinRT window/display's size");
   2.108      }
   2.109  
   2.110 -    if (SDL_AddBasicVideoDisplay(&mode) < 0) {
   2.111 +    if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) {
   2.112 +        return -1;
   2.113 +    }
   2.114 +    if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) {
   2.115          return -1;
   2.116      }
   2.117  
     3.1 --- a/src/video/winrt/SDL_winrtvideo_cpp.h	Sun Jan 26 08:06:36 2014 -0500
     3.2 +++ b/src/video/winrt/SDL_winrtvideo_cpp.h	Sat Mar 01 16:08:16 2014 -0500
     3.3 @@ -44,9 +44,25 @@
     3.4  /* The global, WinRT, video device. */
     3.5  extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice;
     3.6  
     3.7 -/* Computes the current display mode for Plain Direct3D (non-XAML) apps */
     3.8 -extern SDL_DisplayMode WINRT_CalcDisplayModeUsingNativeWindow();
     3.9 -
    3.10 +/* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings.
    3.11 +
    3.12 +   Pass in an allocated SDL_DisplayMode field to store the data in.
    3.13 +
    3.14 +   This function will return 0 on success, -1 on failure.
    3.15 +
    3.16 +   If this function succeeds, be sure to call SDL_free on the
    3.17 +   SDL_DisplayMode's driverdata field.
    3.18 +*/
    3.19 +extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode);
    3.20 +
    3.21 +/* Duplicates a display mode, copying over driverdata as necessary */
    3.22 +extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src);
    3.23 +
    3.24 +/* Display mode internals */
    3.25 +typedef struct
    3.26 +{
    3.27 +    Windows::Graphics::Display::DisplayOrientations currentOrientation;
    3.28 +} SDL_DisplayModeData;
    3.29  
    3.30  #ifdef __cplusplus_winrt
    3.31