add in High DPI support (aka Retina)
authorEdward Rudd <urkle@outoforder.cc>
Fri, 20 Sep 2013 13:43:00 -0400
changeset 77466a05d7352575
parent 7745 c52d519d104a
child 7747 0ebf642117f4
add in High DPI support (aka Retina)

- based on Jørgen's patch with a few bug fixes
include/SDL_hints.h
include/SDL_video.h
src/render/SDL_render.c
src/render/opengl/SDL_render_gl.c
src/test/SDL_test_common.c
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/cocoa/SDL_cocoaopengl.h
src/video/cocoa/SDL_cocoaopengl.m
src/video/cocoa/SDL_cocoavideo.m
src/video/cocoa/SDL_cocoawindow.m
test/testgl2.c
     1.1 --- a/include/SDL_hints.h	Fri Sep 27 22:09:51 2013 -0700
     1.2 +++ b/include/SDL_hints.h	Fri Sep 20 13:43:00 2013 -0400
     1.3 @@ -257,6 +257,11 @@
     1.4  #define SDL_HINT_TIMER_RESOLUTION "SDL_TIMER_RESOLUTION"
     1.5  
     1.6  
     1.7 +/**
     1.8 + *  \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac)
     1.9 + */
    1.10 +#define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_HIGHDPI_DISABLED"
    1.11 +
    1.12  
    1.13  /**
    1.14   *  \brief  An enumeration of hint priorities
     2.1 --- a/include/SDL_video.h	Fri Sep 27 22:09:51 2013 -0700
     2.2 +++ b/include/SDL_video.h	Fri Sep 20 13:43:00 2013 -0400
     2.3 @@ -107,7 +107,8 @@
     2.4      SDL_WINDOW_INPUT_FOCUS = 0x00000200,        /**< window has input focus */
     2.5      SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
     2.6      SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
     2.7 -    SDL_WINDOW_FOREIGN = 0x00000800             /**< window not created by SDL */
     2.8 +    SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */
     2.9 +    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported */
    2.10  } SDL_WindowFlags;
    2.11  
    2.12  /**
    2.13 @@ -393,10 +394,11 @@
    2.14   *  \param w     The width of the window.
    2.15   *  \param h     The height of the window.
    2.16   *  \param flags The flags for the window, a mask of any of the following:
    2.17 - *               ::SDL_WINDOW_FULLSCREEN, ::SDL_WINDOW_OPENGL,
    2.18 - *               ::SDL_WINDOW_HIDDEN,     ::SDL_WINDOW_BORDERLESS,
    2.19 - *               ::SDL_WINDOW_RESIZABLE,  ::SDL_WINDOW_MAXIMIZED,
    2.20 - *               ::SDL_WINDOW_MINIMIZED,  ::SDL_WINDOW_INPUT_GRABBED.
    2.21 + *               ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
    2.22 + *               ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
    2.23 + *               ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
    2.24 + *               ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
    2.25 + *               ::SDL_WINDOW_ALLOW_HIGHDPI.
    2.26   *
    2.27   *  \return The id of the window created, or zero if window creation failed.
    2.28   *
    2.29 @@ -900,6 +902,23 @@
    2.30  extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_GetCurrentContext(void);
    2.31  
    2.32  /**
    2.33 + *  \brief Get the size of a window's underlying drawable (for use with glViewport).
    2.34 + *
    2.35 + *  \param w        Pointer to variable for storing the width, may be NULL
    2.36 + *  \param h        Pointer to variable for storing the height, may be NULL
    2.37 + *
    2.38 + * This may differ from SDL_GetWindowSize if we're rendering to a high-DPI
    2.39 + * drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a
    2.40 + * platform with high-DPI support (Apple calls this "Retina"), and not disabled
    2.41 + * by the SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
    2.42 + *
    2.43 + *  \sa SDL_GetWindowSize()
    2.44 + *  \sa SDL_CreateWindow()
    2.45 + */
    2.46 +extern DECLSPEC void SDLCALL SDL_GL_GetDrawableSize(SDL_Window * window, int *w,
    2.47 +                                                    int *h);
    2.48 +
    2.49 +/**
    2.50   *  \brief Set the swap interval for the current OpenGL context.
    2.51   *
    2.52   *  \param interval 0 for immediate updates, 1 for updates synchronized with the
     3.1 --- a/src/render/SDL_render.c	Fri Sep 27 22:09:51 2013 -0700
     3.2 +++ b/src/render/SDL_render.c	Fri Sep 20 13:43:00 2013 -0400
     3.3 @@ -117,7 +117,12 @@
     3.4                      /* Window was resized, reset viewport */
     3.5                      int w, h;
     3.6  
     3.7 -                    SDL_GetWindowSize(window, &w, &h);
     3.8 +                    if (renderer->GetOutputSize) {
     3.9 +                        renderer->GetOutputSize(renderer, &w, &h);
    3.10 +                    } else {
    3.11 +                        SDL_GetWindowSize(renderer->window, &w, &h);
    3.12 +                    }
    3.13 +
    3.14                      if (renderer->target) {
    3.15                          renderer->viewport_backup.x = 0;
    3.16                          renderer->viewport_backup.y = 0;
    3.17 @@ -335,11 +340,11 @@
    3.18  
    3.19      if (renderer->target) {
    3.20          return SDL_QueryTexture(renderer->target, NULL, NULL, w, h);
    3.21 +    } else if (renderer->GetOutputSize) {
    3.22 +        return renderer->GetOutputSize(renderer, w, h);
    3.23      } else if (renderer->window) {
    3.24          SDL_GetWindowSize(renderer->window, w, h);
    3.25          return 0;
    3.26 -    } else if (renderer->GetOutputSize) {
    3.27 -        return renderer->GetOutputSize(renderer, w, h);
    3.28      } else {
    3.29          /* This should never happen */
    3.30          SDL_SetError("Renderer doesn't support querying output size");
     4.1 --- a/src/render/opengl/SDL_render_gl.c	Fri Sep 27 22:09:51 2013 -0700
     4.2 +++ b/src/render/opengl/SDL_render_gl.c	Fri Sep 20 13:43:00 2013 -0400
     4.3 @@ -47,6 +47,7 @@
     4.4  static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
     4.5  static void GL_WindowEvent(SDL_Renderer * renderer,
     4.6                             const SDL_WindowEvent *event);
     4.7 +static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
     4.8  static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
     4.9  static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    4.10                              const SDL_Rect * rect, const void *pixels,
    4.11 @@ -399,6 +400,7 @@
    4.12      }
    4.13  
    4.14      renderer->WindowEvent = GL_WindowEvent;
    4.15 +    renderer->GetOutputSize = GL_GetOutputSize;
    4.16      renderer->CreateTexture = GL_CreateTexture;
    4.17      renderer->UpdateTexture = GL_UpdateTexture;
    4.18      renderer->LockTexture = GL_LockTexture;
    4.19 @@ -539,6 +541,14 @@
    4.20      }
    4.21  }
    4.22  
    4.23 +static int
    4.24 +GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
    4.25 +{
    4.26 +    SDL_GL_GetDrawableSize(renderer->window, w, h);
    4.27 +
    4.28 +    return 0;
    4.29 +}
    4.30 +
    4.31  SDL_FORCE_INLINE int
    4.32  power_of_2(int input)
    4.33  {
     5.1 --- a/src/test/SDL_test_common.c	Fri Sep 27 22:09:51 2013 -0700
     5.2 +++ b/src/test/SDL_test_common.c	Fri Sep 20 13:43:00 2013 -0400
     5.3 @@ -27,7 +27,7 @@
     5.4  #include <stdio.h>
     5.5  
     5.6  #define VIDEO_USAGE \
     5.7 -"[--video driver] [--renderer driver] [--gldebug] [--info all|video|modes|render|event] [--log all|error|system|audio|video|render|input] [--display N] [--fullscreen | --fullscreen-desktop | --windows N] [--title title] [--icon icon.bmp] [--center | --position X,Y] [--geometry WxH] [--min-geometry WxH] [--max-geometry WxH] [--logical WxH] [--scale N] [--depth N] [--refresh R] [--vsync] [--noframe] [--resize] [--minimize] [--maximize] [--grab]"
     5.8 +"[--video driver] [--renderer driver] [--gldebug] [--info all|video|modes|render|event] [--log all|error|system|audio|video|render|input] [--display N] [--fullscreen | --fullscreen-desktop | --windows N] [--title title] [--icon icon.bmp] [--center | --position X,Y] [--geometry WxH] [--min-geometry WxH] [--max-geometry WxH] [--logical WxH] [--scale N] [--depth N] [--refresh R] [--vsync] [--noframe] [--resize] [--minimize] [--maximize] [--grab] [--allow-hidpi]"
     5.9  
    5.10  #define AUDIO_USAGE \
    5.11  "[--rate N] [--format U8|S8|U16|U16LE|U16BE|S16|S16LE|S16BE] [--channels N] [--samples N]"
    5.12 @@ -194,6 +194,10 @@
    5.13          state->num_windows = 1;
    5.14          return 1;
    5.15      }
    5.16 +    if (SDL_strcasecmp(argv[index], "--allow-highdpi") == 0) {
    5.17 +        state->window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
    5.18 +        return 1;
    5.19 +    }
    5.20      if (SDL_strcasecmp(argv[index], "--windows") == 0) {
    5.21          ++index;
    5.22          if (!argv[index] || !SDL_isdigit(*argv[index])) {
     6.1 --- a/src/video/SDL_sysvideo.h	Fri Sep 27 22:09:51 2013 -0700
     6.2 +++ b/src/video/SDL_sysvideo.h	Fri Sep 20 13:43:00 2013 -0400
     6.3 @@ -224,6 +224,7 @@
     6.4      void (*GL_UnloadLibrary) (_THIS);
     6.5        SDL_GLContext(*GL_CreateContext) (_THIS, SDL_Window * window);
     6.6      int (*GL_MakeCurrent) (_THIS, SDL_Window * window, SDL_GLContext context);
     6.7 +    void (*GL_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h);
     6.8      int (*GL_SetSwapInterval) (_THIS, int interval);
     6.9      int (*GL_GetSwapInterval) (_THIS);
    6.10      void (*GL_SwapWindow) (_THIS, SDL_Window * window);
     7.1 --- a/src/video/SDL_video.c	Fri Sep 27 22:09:51 2013 -0700
     7.2 +++ b/src/video/SDL_video.c	Fri Sep 20 13:43:00 2013 -0400
     7.3 @@ -1187,6 +1187,7 @@
     7.4  SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
     7.5  {
     7.6      SDL_Window *window;
     7.7 +    const char *hint;
     7.8  
     7.9      if (!_this) {
    7.10          /* Initialize the video system if needed */
    7.11 @@ -1245,6 +1246,17 @@
    7.12      window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
    7.13      window->brightness = 1.0f;
    7.14      window->next = _this->windows;
    7.15 +
    7.16 +    /* Unless the user has specified the high-DPI disabling hint, respect the
    7.17 +     * SDL_WINDOW_ALLOW_HIGHDPI flag.
    7.18 +     */
    7.19 +    hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
    7.20 +    if (!hint || *hint != '1') {
    7.21 +        if ((flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
    7.22 +            window->flags |= SDL_WINDOW_ALLOW_HIGHDPI;
    7.23 +        }
    7.24 +    }
    7.25 +
    7.26      if (_this->windows) {
    7.27          _this->windows->prev = window;
    7.28      }
    7.29 @@ -2813,6 +2825,17 @@
    7.30      return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
    7.31  }
    7.32  
    7.33 +void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
    7.34 +{
    7.35 +    CHECK_WINDOW_MAGIC(window, );
    7.36 +
    7.37 +    if (_this->GL_GetDrawableSize) {
    7.38 +        _this->GL_GetDrawableSize(_this, window, w, h);
    7.39 +    } else {
    7.40 +        SDL_GetWindowSize(window, w, h);
    7.41 +    }
    7.42 +}
    7.43 +
    7.44  int
    7.45  SDL_GL_SetSwapInterval(int interval)
    7.46  {
     8.1 --- a/src/video/cocoa/SDL_cocoaopengl.h	Fri Sep 27 22:09:51 2013 -0700
     8.2 +++ b/src/video/cocoa/SDL_cocoaopengl.h	Fri Sep 20 13:43:00 2013 -0400
     8.3 @@ -54,6 +54,8 @@
     8.4  extern SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window * window);
     8.5  extern int Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window,
     8.6                                  SDL_GLContext context);
     8.7 +extern void Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window,
     8.8 +                                     int * w, int * h);
     8.9  extern int Cocoa_GL_SetSwapInterval(_THIS, int interval);
    8.10  extern int Cocoa_GL_GetSwapInterval(_THIS);
    8.11  extern void Cocoa_GL_SwapWindow(_THIS, SDL_Window * window);
     9.1 --- a/src/video/cocoa/SDL_cocoaopengl.m	Fri Sep 27 22:09:51 2013 -0700
     9.2 +++ b/src/video/cocoa/SDL_cocoaopengl.m	Fri Sep 20 13:43:00 2013 -0400
     9.3 @@ -35,6 +35,18 @@
     9.4  
     9.5  #define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
     9.6  
     9.7 +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
     9.8 +/* New methods for converting to and from backing store pixels, taken from
     9.9 + * AppKite/NSView.h in 10.8 SDK. */
    9.10 +@interface NSView (Backing)
    9.11 +- (NSPoint)convertPointToBacking:(NSPoint)aPoint;
    9.12 +- (NSPoint)convertPointFromBacking:(NSPoint)aPoint;
    9.13 +- (NSSize)convertSizeToBacking:(NSSize)aSize;
    9.14 +- (NSSize)convertSizeFromBacking:(NSSize)aSize;
    9.15 +- (NSRect)convertRectToBacking:(NSRect)aRect;
    9.16 +- (NSRect)convertRectFromBacking:(NSRect)aRect;
    9.17 +@end
    9.18 +#endif
    9.19  
    9.20  #ifndef kCGLPFAOpenGLProfile
    9.21  #define kCGLPFAOpenGLProfile 99
    9.22 @@ -294,6 +306,28 @@
    9.23      return 0;
    9.24  }
    9.25  
    9.26 +void
    9.27 +Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
    9.28 +{
    9.29 +    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
    9.30 +    NSView *contentView = [windata->nswindow contentView];
    9.31 +    NSRect viewport = [contentView bounds];
    9.32 +
    9.33 +    /* This gives us the correct viewport for a Retina-enabled view, only
    9.34 +     * supported on 10.7+. */
    9.35 +    if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
    9.36 +        viewport = [contentView convertRectToBacking:viewport];
    9.37 +    }
    9.38 +
    9.39 +    if (w) {
    9.40 +        *w = viewport.size.width;
    9.41 +    }
    9.42 +
    9.43 +    if (h) {
    9.44 +        *h = viewport.size.height;
    9.45 +    }
    9.46 +}
    9.47 +
    9.48  int
    9.49  Cocoa_GL_SetSwapInterval(_THIS, int interval)
    9.50  {
    10.1 --- a/src/video/cocoa/SDL_cocoavideo.m	Fri Sep 27 22:09:51 2013 -0700
    10.2 +++ b/src/video/cocoa/SDL_cocoavideo.m	Fri Sep 20 13:43:00 2013 -0400
    10.3 @@ -119,6 +119,7 @@
    10.4      device->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary;
    10.5      device->GL_CreateContext = Cocoa_GL_CreateContext;
    10.6      device->GL_MakeCurrent = Cocoa_GL_MakeCurrent;
    10.7 +    device->GL_GetDrawableSize = Cocoa_GL_GetDrawableSize;
    10.8      device->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval;
    10.9      device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
   10.10      device->GL_SwapWindow = Cocoa_GL_SwapWindow;
    11.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Fri Sep 27 22:09:51 2013 -0700
    11.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Fri Sep 20 13:43:00 2013 -0400
    11.3 @@ -34,6 +34,13 @@
    11.4  #include "SDL_cocoamouse.h"
    11.5  #include "SDL_cocoaopengl.h"
    11.6  
    11.7 +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
    11.8 +/* Taken from AppKit/NSOpenGLView.h in 10.8 SDK. */
    11.9 +@interface NSView (NSOpenGLSurfaceResolution)
   11.10 +- (BOOL)wantsBestResolutionOpenGLSurface;
   11.11 +- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
   11.12 +@end
   11.13 +#endif
   11.14  
   11.15  static Uint32 s_moveHack;
   11.16  
   11.17 @@ -739,6 +746,13 @@
   11.18      /* Create a default view for this window */
   11.19      rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   11.20      NSView *contentView = [[SDLView alloc] initWithFrame:rect];
   11.21 +
   11.22 +    if ((window->flags & SDL_WINDOW_ALLOW_HIGHDPI) > 0) {
   11.23 +        if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
   11.24 +            [contentView setWantsBestResolutionOpenGLSurface:YES];
   11.25 +        }
   11.26 +    }
   11.27 +
   11.28      [nswindow setContentView: contentView];
   11.29      [contentView release];
   11.30  
    12.1 --- a/test/testgl2.c	Fri Sep 27 22:09:51 2013 -0700
    12.2 +++ b/test/testgl2.c	Fri Sep 20 13:43:00 2013 -0400
    12.3 @@ -180,6 +180,7 @@
    12.4      SDL_Event event;
    12.5      Uint32 then, now, frames;
    12.6      int status;
    12.7 +    int dw, dh;
    12.8  
    12.9      /* Enable standard application logging */
   12.10      SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
   12.11 @@ -254,6 +255,10 @@
   12.12      SDL_GetCurrentDisplayMode(0, &mode);
   12.13      SDL_Log("Screen BPP    : %d\n", SDL_BITSPERPIXEL(mode.format));
   12.14      SDL_Log("Swap Interval : %d\n", SDL_GL_GetSwapInterval());
   12.15 +    SDL_GetWindowSize(state->windows[0], &dw, &dh);
   12.16 +    SDL_Log("Window Size   : %d,%d\n", dw, dh);
   12.17 +    SDL_GL_GetDrawableSize(state->windows[0], &dw, &dh);
   12.18 +    SDL_Log("Draw Size     : %d,%d\n", dw, dh);
   12.19      SDL_Log("\n");
   12.20      SDL_Log("Vendor        : %s\n", glGetString(GL_VENDOR));
   12.21      SDL_Log("Renderer      : %s\n", glGetString(GL_RENDERER));
   12.22 @@ -322,7 +327,7 @@
   12.23      glEnable(GL_DEPTH_TEST);
   12.24      glDepthFunc(GL_LESS);
   12.25      glShadeModel(GL_SMOOTH);
   12.26 -
   12.27 +    
   12.28      /* Main render loop */
   12.29      frames = 0;
   12.30      then = SDL_GetTicks();
   12.31 @@ -336,7 +341,7 @@
   12.32          for (i = 0; i < state->num_windows; ++i) {
   12.33              int w, h;
   12.34              SDL_GL_MakeCurrent(state->windows[i], context);
   12.35 -            SDL_GetWindowSize(state->windows[i], &w, &h);
   12.36 +            SDL_GL_GetDrawableSize(state->windows[i], &w, &h);
   12.37              glViewport(0, 0, w, h);
   12.38              Render();
   12.39              SDL_GL_SwapWindow(state->windows[i]);