src/video/x11/SDL_x11framebuffer.c
author Sam Lantinga
Tue, 08 Feb 2011 16:50:51 -0800
changeset 5229 c015d3e63631
parent 5182 073b86030262
child 5262 b530ef003506
permissions -rw-r--r--
Fixed setting the texture unit, still doesn't work.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_x11video.h"
    25 #include "SDL_x11framebuffer.h"
    26 
    27 
    28 #ifndef NO_SHARED_MEMORY
    29 
    30 /* Shared memory error handler routine */
    31 static int shm_error;
    32 static int (*X_handler)(Display *, XErrorEvent *) = NULL;
    33 static int shm_errhandler(Display *d, XErrorEvent *e)
    34 {
    35         if ( e->error_code == BadAccess ) {
    36             shm_error = True;
    37             return(0);
    38         } else
    39         return(X_handler(d,e));
    40 }
    41 
    42 static SDL_bool have_mitshm(void)
    43 {
    44     /* Only use shared memory on local X servers */
    45     if ( (SDL_strncmp(XDisplayName(NULL), ":", 1) == 0) ||
    46          (SDL_strncmp(XDisplayName(NULL), "unix:", 5) == 0) ) {
    47         return SDL_X11_HAVE_SHM;
    48     }
    49     return SDL_FALSE;
    50 }
    51 
    52 #endif /* !NO_SHARED_MEMORY */
    53 
    54 int
    55 X11_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format,
    56                             void ** pixels, int *pitch)
    57 {
    58     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    59     Display *display = data->videodata->display;
    60     XGCValues gcv;
    61     XVisualInfo vinfo;
    62 
    63     /* Free the old framebuffer surface */
    64     X11_DestroyWindowFramebuffer(_this, window);
    65 
    66     /* Create the graphics context for drawing */
    67     gcv.graphics_exposures = False;
    68     data->gc = XCreateGC(display, data->xwindow, GCGraphicsExposures, &gcv);
    69     if (!data->gc) {
    70         SDL_SetError("Couldn't create graphics context");
    71         return -1;
    72     }
    73 
    74     /* Find out the pixel format and depth */
    75     if (X11_GetVisualInfoFromVisual(display, data->visual, &vinfo) < 0) {
    76         SDL_SetError("Couldn't get window visual information");
    77         return -1;
    78     }
    79 
    80     *format = X11_GetPixelFormatFromVisualInfo(display, &vinfo);
    81     if (*format == SDL_PIXELFORMAT_UNKNOWN) {
    82         SDL_SetError("Unknown window pixel format");
    83         return -1;
    84     }
    85 
    86     /* Calculate pitch */
    87     *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
    88 
    89     /* Create the actual image */
    90 #ifndef NO_SHARED_MEMORY
    91     if (have_mitshm()) {
    92         XShmSegmentInfo *shminfo = &data->shminfo;
    93 
    94         shminfo->shmid = shmget(IPC_PRIVATE, window->h*(*pitch), IPC_CREAT | 0777);
    95         if ( shminfo->shmid >= 0 ) {
    96             shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
    97             shminfo->readOnly = False;
    98             if ( shminfo->shmaddr != (char *)-1 ) {
    99                 shm_error = False;
   100                 X_handler = XSetErrorHandler(shm_errhandler);
   101                 XShmAttach(display, shminfo);
   102                 XSync(display, True);
   103                 XSetErrorHandler(X_handler);
   104                 if ( shm_error )
   105                     shmdt(shminfo->shmaddr);
   106             } else {
   107                 shm_error = True;
   108             }
   109             shmctl(shminfo->shmid, IPC_RMID, NULL);
   110         } else {
   111             shm_error = True;
   112         }
   113         if (!shm_error) {
   114             data->ximage = XShmCreateImage(display, data->visual,
   115                              vinfo.depth, ZPixmap,
   116                              shminfo->shmaddr, shminfo, 
   117                              window->w, window->h);
   118             if (!data->ximage) {
   119                 XShmDetach(display, shminfo);
   120                 XSync(display, False);
   121                 shmdt(shminfo->shmaddr);
   122             } else {
   123                 /* Done! */
   124                 data->use_mitshm = SDL_TRUE;
   125                 *pixels = shminfo->shmaddr;
   126                 return 0;
   127             }
   128         }
   129     }
   130 #endif /* not NO_SHARED_MEMORY */
   131 
   132     *pixels = SDL_malloc(window->h*(*pitch));
   133     if (*pixels == NULL) {
   134         SDL_OutOfMemory();
   135         return -1;
   136     }
   137 
   138     data->ximage = XCreateImage(display, data->visual,
   139                       vinfo.depth, ZPixmap, 0, (char *)(*pixels), 
   140                       window->w, window->h, 32, 0);
   141     if (!data->ximage) {
   142         SDL_free(*pixels);
   143         SDL_SetError("Couldn't create XImage");
   144         return -1;
   145     }
   146     return 0;
   147 }
   148 
   149 int
   150 X11_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
   151                             int numrects, SDL_Rect * rects)
   152 {
   153     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   154     Display *display = data->videodata->display;
   155     int i;
   156     SDL_Rect *rect;
   157 
   158 #ifndef NO_SHARED_MEMORY
   159     if (data->use_mitshm) {
   160         for (i = 0; i < numrects; ++i) {
   161             rect = &rects[i];
   162 
   163             if (rect->w == 0 || rect->h == 0) { /* Clipped? */
   164                 continue;
   165             }
   166             XShmPutImage(display, data->xwindow, data->gc, data->ximage,
   167                     rect->x, rect->y,
   168                     rect->x, rect->y, rect->w, rect->h, False);
   169         }
   170     }
   171     else
   172 #endif /* !NO_SHARED_MEMORY */
   173     {
   174         for (i = 0; i < numrects; ++i) {
   175             rect = &rects[i];
   176 
   177             if (rect->w == 0 || rect->h == 0) { /* Clipped? */
   178                 continue;
   179             }
   180             XPutImage(display, data->xwindow, data->gc, data->ximage,
   181                   rect->x, rect->y,
   182                   rect->x, rect->y, rect->w, rect->h);
   183         }
   184     }
   185     XSync(display, False);
   186 }
   187 
   188 void
   189 X11_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
   190 {
   191     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   192     Display *display = data->videodata->display;
   193 
   194     if (data->ximage) {
   195         XDestroyImage(data->ximage);
   196 
   197 #ifndef NO_SHARED_MEMORY
   198         if (data->use_mitshm) {
   199             XShmDetach(display, &data->shminfo);
   200             XSync(display, False);
   201             shmdt(data->shminfo.shmaddr);
   202             data->use_mitshm = SDL_FALSE;
   203         }
   204 #endif /* !NO_SHARED_MEMORY */
   205 
   206         data->ximage = NULL;
   207     }
   208     if (data->gc) {
   209         XFreeGC(display, data->gc);
   210         data->gc = NULL;
   211     }
   212 }
   213 
   214 /* vi: set ts=4 sw=4 expandtab: */