src/video/x11/SDL_x11framebuffer.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 09 Apr 2015 22:28:37 -0400
changeset 9541 cf8fab52e33b
parent 8149 681eb46b8ac4
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Merged Alex Szpakowski's iOS-improvement branch to default.

Fixes Bugzilla #2798.
Fixes Bugzilla #2212.
Fixes Bugzilla #2826.
Fixes Bugzilla #2661.
Fixes Bugzilla #1885.
Fixes Bugzilla #1578.
Fixes Bugzilla #2751.

(whew!)

Notable changes, from Alex's notes:

- The SDL_WINDOW_ALLOW_HIGHDPI flag is now needed (along with SDL_GL_GetDrawableSize or SDL_GetRendererOutputSize) to use Retina / high DPI resolutions, bringing SDL’s Retina-related behavior on iOS in line with Mac OS X. Window dimensions and display modes are now in the “points” (non-high DPI) coordinate system rather than pixels, whereas SDL_GL_GetDrawableSize is in pixels.

- Reworked the custom extended launch screen code:
- It now hides after the first SDL_PumpEvents call rather than SDL_CreateWindow, and it fades out in a similar manner to the system launch screen behavior.
- It now mirrors the system launch screen behavior when deciding which image to display: it falls back to using the Launch Images dictionary in Info.plist if the iOS 8+ launch screen nib isn’t available, and if the Launch Images dictionary doesn’t exist it uses the old standard launch image names.
- The extended launch screen can now be disabled via the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h.

- Added support for SDL_HINT_ACCELEROMETER_AS_JOYSTICK.

- Added access to a window view's renderbuffer and framebuffer to syswm.

- Added OpenGL ES debug labels for the Renderbuffer and Framebuffer Objects created with SDL_GL_CreateContext.

- Added support for sRGB OpenGL ES contexts on iOS 7+.

- Updated OpenGL ES contexts to support native-resolution rendering (when SDL_WINDOW_ALLOW_HIGHDPI is enabled) on the iPhone 6 Plus, i.e. 1080x1920 rather than 1242x2208.

- Updated SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext to be more robust.

- Updated SDL windows to display a UIView at all times, even when an OpenGL context is not active. This allows rotation, touch events, and other windowing-related events to work properly without an active OpenGL context. It also makes it easier to use SDL_GetWindowWMInfo after creating a SDL window.

- Updated the iOS-specific Objective-C code to use cleaner and more modern language features and APIs, including ARC instead of manual reference counting.

- Updated SDL_HINT_ORIENTATIONS to allow disabling custom orientations if the hint is set with no valid orientation names.

- Fixed several rotation and orientation bugs with windows and display modes, especially in iOS 8+.

- Fixed SDL_SetWindowFullscreen failing to update the status bar visibility on iOS 7+.

- Fixed the orientation of the offset applied to the window’s view when the onscreen keyboard is shown in iOS 8+.

- Fixed SDL_IsScreenKeyboardShown (patch by Phil Hassey.)

- Fixed several major memory leaks caused by missing autorelease pool blocks in the iOS-specific Objective-C code.

- Removed several dead code paths.

- The iOS 7 SDK (Xcode 5) or newer is now required to build SDL for iOS.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "SDL_x11video.h"
    26 #include "SDL_x11framebuffer.h"
    27 
    28 
    29 #ifndef NO_SHARED_MEMORY
    30 
    31 /* Shared memory error handler routine */
    32 static int shm_error;
    33 static int (*X_handler)(Display *, XErrorEvent *) = NULL;
    34 static int shm_errhandler(Display *d, XErrorEvent *e)
    35 {
    36         if ( e->error_code == BadAccess ) {
    37             shm_error = True;
    38             return(0);
    39         } else
    40         return(X_handler(d,e));
    41 }
    42 
    43 static SDL_bool have_mitshm(void)
    44 {
    45     /* Only use shared memory on local X servers */
    46     if ( (SDL_strncmp(X11_XDisplayName(NULL), ":", 1) == 0) ||
    47          (SDL_strncmp(X11_XDisplayName(NULL), "unix:", 5) == 0) ) {
    48         return SDL_X11_HAVE_SHM;
    49     }
    50     return SDL_FALSE;
    51 }
    52 
    53 #endif /* !NO_SHARED_MEMORY */
    54 
    55 int
    56 X11_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format,
    57                             void ** pixels, int *pitch)
    58 {
    59     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    60     Display *display = data->videodata->display;
    61     XGCValues gcv;
    62     XVisualInfo vinfo;
    63 
    64     /* Free the old framebuffer surface */
    65     X11_DestroyWindowFramebuffer(_this, window);
    66 
    67     /* Create the graphics context for drawing */
    68     gcv.graphics_exposures = False;
    69     data->gc = X11_XCreateGC(display, data->xwindow, GCGraphicsExposures, &gcv);
    70     if (!data->gc) {
    71         return SDL_SetError("Couldn't create graphics context");
    72     }
    73 
    74     /* Find out the pixel format and depth */
    75     if (X11_GetVisualInfoFromVisual(display, data->visual, &vinfo) < 0) {
    76         return SDL_SetError("Couldn't get window visual information");
    77     }
    78 
    79     *format = X11_GetPixelFormatFromVisualInfo(display, &vinfo);
    80     if (*format == SDL_PIXELFORMAT_UNKNOWN) {
    81         return SDL_SetError("Unknown window pixel format");
    82     }
    83 
    84     /* Calculate pitch */
    85     *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
    86 
    87     /* Create the actual image */
    88 #ifndef NO_SHARED_MEMORY
    89     if (have_mitshm()) {
    90         XShmSegmentInfo *shminfo = &data->shminfo;
    91 
    92         shminfo->shmid = shmget(IPC_PRIVATE, window->h*(*pitch), IPC_CREAT | 0777);
    93         if ( shminfo->shmid >= 0 ) {
    94             shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
    95             shminfo->readOnly = False;
    96             if ( shminfo->shmaddr != (char *)-1 ) {
    97                 shm_error = False;
    98                 X_handler = X11_XSetErrorHandler(shm_errhandler);
    99                 X11_XShmAttach(display, shminfo);
   100                 X11_XSync(display, True);
   101                 X11_XSetErrorHandler(X_handler);
   102                 if ( shm_error )
   103                     shmdt(shminfo->shmaddr);
   104             } else {
   105                 shm_error = True;
   106             }
   107             shmctl(shminfo->shmid, IPC_RMID, NULL);
   108         } else {
   109             shm_error = True;
   110         }
   111         if (!shm_error) {
   112             data->ximage = X11_XShmCreateImage(display, data->visual,
   113                              vinfo.depth, ZPixmap,
   114                              shminfo->shmaddr, shminfo,
   115                              window->w, window->h);
   116             if (!data->ximage) {
   117                 X11_XShmDetach(display, shminfo);
   118                 X11_XSync(display, False);
   119                 shmdt(shminfo->shmaddr);
   120             } else {
   121                 /* Done! */
   122                 data->use_mitshm = SDL_TRUE;
   123                 *pixels = shminfo->shmaddr;
   124                 return 0;
   125             }
   126         }
   127     }
   128 #endif /* not NO_SHARED_MEMORY */
   129 
   130     *pixels = SDL_malloc(window->h*(*pitch));
   131     if (*pixels == NULL) {
   132         return SDL_OutOfMemory();
   133     }
   134 
   135     data->ximage = X11_XCreateImage(display, data->visual,
   136                       vinfo.depth, ZPixmap, 0, (char *)(*pixels),
   137                       window->w, window->h, 32, 0);
   138     if (!data->ximage) {
   139         SDL_free(*pixels);
   140         return SDL_SetError("Couldn't create XImage");
   141     }
   142     return 0;
   143 }
   144 
   145 int
   146 X11_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects,
   147                             int numrects)
   148 {
   149     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   150     Display *display = data->videodata->display;
   151     int i;
   152     int x, y, w ,h;
   153 #ifndef NO_SHARED_MEMORY
   154     if (data->use_mitshm) {
   155         for (i = 0; i < numrects; ++i) {
   156             x = rects[i].x;
   157             y = rects[i].y;
   158             w = rects[i].w;
   159             h = rects[i].h;
   160 
   161             if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
   162                 /* Clipped? */
   163                 continue;
   164             }
   165             if (x < 0)
   166             {
   167                 x += w;
   168                 w += rects[i].x;
   169             }
   170             if (y < 0)
   171             {
   172                 y += h;
   173                 h += rects[i].y;
   174             }
   175             if (x + w > window->w)
   176                 w = window->w - x;
   177             if (y + h > window->h)
   178                 h = window->h - y;
   179 
   180             X11_XShmPutImage(display, data->xwindow, data->gc, data->ximage,
   181                 x, y, x, y, w, h, False);
   182         }
   183     }
   184     else
   185 #endif /* !NO_SHARED_MEMORY */
   186     {
   187         for (i = 0; i < numrects; ++i) {
   188             x = rects[i].x;
   189             y = rects[i].y;
   190             w = rects[i].w;
   191             h = rects[i].h;
   192 
   193             if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
   194                 /* Clipped? */
   195                 continue;
   196             }
   197             if (x < 0)
   198             {
   199                 x += w;
   200                 w += rects[i].x;
   201             }
   202             if (y < 0)
   203             {
   204                 y += h;
   205                 h += rects[i].y;
   206             }
   207             if (x + w > window->w)
   208                 w = window->w - x;
   209             if (y + h > window->h)
   210                 h = window->h - y;
   211 
   212             X11_XPutImage(display, data->xwindow, data->gc, data->ximage,
   213                 x, y, x, y, w, h);
   214         }
   215     }
   216 
   217     X11_XSync(display, False);
   218 
   219     return 0;
   220 }
   221 
   222 void
   223 X11_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
   224 {
   225     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   226     Display *display;
   227 
   228     if (!data) {
   229         /* The window wasn't fully initialized */
   230         return;
   231     }
   232 
   233     display = data->videodata->display;
   234 
   235     if (data->ximage) {
   236         XDestroyImage(data->ximage);
   237 
   238 #ifndef NO_SHARED_MEMORY
   239         if (data->use_mitshm) {
   240             X11_XShmDetach(display, &data->shminfo);
   241             X11_XSync(display, False);
   242             shmdt(data->shminfo.shmaddr);
   243             data->use_mitshm = SDL_FALSE;
   244         }
   245 #endif /* !NO_SHARED_MEMORY */
   246 
   247         data->ximage = NULL;
   248     }
   249     if (data->gc) {
   250         X11_XFreeGC(display, data->gc);
   251         data->gc = NULL;
   252     }
   253 }
   254 
   255 #endif /* SDL_VIDEO_DRIVER_X11 */
   256 
   257 /* vi: set ts=4 sw=4 expandtab: */