src/video/x11/SDL_x11render.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Dec 2009 08:11:06 +0000
changeset 3565 f43c8f688f77
parent 3559 5f26a7eb5ff0
child 3596 f638ded38b8a
permissions -rw-r--r--
Fixed bug #906

Added better error reporting for OpenGL context creation failing.
     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 #if SDL_VIDEO_RENDER_X11
    25 
    26 #include <limits.h> /* For INT_MIN and INT_MAX */
    27 
    28 #include "SDL_x11video.h"
    29 #include "../SDL_rect_c.h"
    30 #include "../SDL_pixels_c.h"
    31 #include "../SDL_yuv_sw_c.h"
    32 
    33 /* X11 renderer implementation */
    34 
    35 static SDL_Renderer *X11_CreateRenderer(SDL_Window * window, Uint32 flags);
    36 static int X11_DisplayModeChanged(SDL_Renderer * renderer);
    37 static int X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    38 static int X11_QueryTexturePixels(SDL_Renderer * renderer,
    39                                   SDL_Texture * texture, void **pixels,
    40                                   int *pitch);
    41 static int X11_SetTextureBlendMode(SDL_Renderer * renderer,
    42                                    SDL_Texture * texture);
    43 static int X11_SetTextureScaleMode(SDL_Renderer * renderer,
    44                                    SDL_Texture * texture);
    45 static int X11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    46                              const SDL_Rect * rect, const void *pixels,
    47                              int pitch);
    48 static int X11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    49                            const SDL_Rect * rect, int markDirty,
    50                            void **pixels, int *pitch);
    51 static void X11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    52 static int X11_SetDrawBlendMode(SDL_Renderer * renderer);
    53 static int X11_RenderPoints(SDL_Renderer * renderer, const SDL_Point * points,
    54                             int count);
    55 static int X11_RenderLines(SDL_Renderer * renderer, const SDL_Point * points,
    56                            int count);
    57 static int X11_RenderRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
    58                            int count);
    59 static int X11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    60                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    61 static int X11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    62                                 Uint32 format, void * pixels, int pitch);
    63 static int X11_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    64                                  Uint32 format, const void * pixels, int pitch);
    65 static void X11_RenderPresent(SDL_Renderer * renderer);
    66 static void X11_DestroyTexture(SDL_Renderer * renderer,
    67                                SDL_Texture * texture);
    68 static void X11_DestroyRenderer(SDL_Renderer * renderer);
    69 
    70 
    71 SDL_RenderDriver X11_RenderDriver = {
    72     X11_CreateRenderer,
    73     {
    74      "x11",
    75      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    76       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    77       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED),
    78      SDL_TEXTUREMODULATE_NONE,
    79      SDL_BLENDMODE_NONE,
    80      SDL_TEXTURESCALEMODE_NONE,
    81      0,
    82      {0},
    83      0,
    84      0}
    85 };
    86 
    87 typedef struct
    88 {
    89     Display *display;
    90     int screen;
    91     Visual *visual;
    92     int depth;
    93     int scanline_pad;
    94     Window window;
    95     Pixmap pixmaps[3];
    96     int current_pixmap;
    97     Drawable drawable;
    98     SDL_PixelFormat format;
    99     GC gc;
   100     SDL_DirtyRectList dirty;
   101     SDL_bool makedirty;
   102 } X11_RenderData;
   103 
   104 typedef struct
   105 {
   106     SDL_SW_YUVTexture *yuv;
   107     Uint32 format;
   108     Pixmap pixmap;
   109     XImage *image;
   110 #ifndef NO_SHARED_MEMORY
   111     /* MIT shared memory extension information */
   112     XShmSegmentInfo shminfo;
   113 #endif
   114     XImage *scaling_image;
   115     void *pixels;
   116     int pitch;
   117 } X11_TextureData;
   118 
   119 #ifndef NO_SHARED_MEMORY
   120 /* Shared memory error handler routine */
   121 static int shm_error;
   122 static int (*X_handler) (Display *, XErrorEvent *) = NULL;
   123 static int
   124 shm_errhandler(Display * d, XErrorEvent * e)
   125 {
   126     if (e->error_code == BadAccess) {
   127         shm_error = True;
   128         return (0);
   129     } else {
   130         return (X_handler(d, e));
   131     }
   132 }
   133 #endif /* ! NO_SHARED_MEMORY */
   134 
   135 static void
   136 UpdateYUVTextureData(SDL_Texture * texture)
   137 {
   138     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   139     SDL_Rect rect;
   140 
   141     rect.x = 0;
   142     rect.y = 0;
   143     rect.w = texture->w;
   144     rect.h = texture->h;
   145     SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
   146                         texture->h, data->pixels, data->pitch);
   147 }
   148 
   149 void
   150 X11_AddRenderDriver(_THIS)
   151 {
   152     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   153     SDL_RendererInfo *info = &X11_RenderDriver.info;
   154     SDL_DisplayMode *mode = &SDL_CurrentDisplay.desktop_mode;
   155     int i;
   156 
   157     info->texture_formats[info->num_texture_formats++] = mode->format;
   158     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   159     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   160     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YUY2;
   161     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
   162     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU;
   163 
   164     for (i = 0; i < _this->num_displays; ++i) {
   165         SDL_AddRenderDriver(&_this->displays[i], &X11_RenderDriver);
   166     }
   167 }
   168 
   169 SDL_Renderer *
   170 X11_CreateRenderer(SDL_Window * window, Uint32 flags)
   171 {
   172     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   173     SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
   174     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   175     SDL_Renderer *renderer;
   176     SDL_RendererInfo *info;
   177     X11_RenderData *data;
   178     XGCValues gcv;
   179     int i, n;
   180     int bpp;
   181     Uint32 Rmask, Gmask, Bmask, Amask;
   182 
   183     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   184     if (!renderer) {
   185         SDL_OutOfMemory();
   186         return NULL;
   187     }
   188 
   189     data = (X11_RenderData *) SDL_calloc(1, sizeof(*data));
   190     if (!data) {
   191         X11_DestroyRenderer(renderer);
   192         SDL_OutOfMemory();
   193         return NULL;
   194     }
   195     data->display = windowdata->videodata->display;
   196     data->screen = displaydata->screen;
   197     data->visual = displaydata->visual;
   198     data->depth = displaydata->depth;
   199     data->scanline_pad = displaydata->scanline_pad;
   200     data->window = windowdata->window;
   201 
   202     renderer->DisplayModeChanged = X11_DisplayModeChanged;
   203     renderer->CreateTexture = X11_CreateTexture;
   204     renderer->QueryTexturePixels = X11_QueryTexturePixels;
   205     renderer->SetTextureBlendMode = X11_SetTextureBlendMode;
   206     renderer->SetTextureScaleMode = X11_SetTextureScaleMode;
   207     renderer->UpdateTexture = X11_UpdateTexture;
   208     renderer->LockTexture = X11_LockTexture;
   209     renderer->UnlockTexture = X11_UnlockTexture;
   210     renderer->SetDrawBlendMode = X11_SetDrawBlendMode;
   211     renderer->RenderPoints = X11_RenderPoints;
   212     renderer->RenderLines = X11_RenderLines;
   213     renderer->RenderRects = X11_RenderRects;
   214     renderer->RenderCopy = X11_RenderCopy;
   215     renderer->RenderReadPixels = X11_RenderReadPixels;
   216     renderer->RenderWritePixels = X11_RenderWritePixels;
   217     renderer->RenderPresent = X11_RenderPresent;
   218     renderer->DestroyTexture = X11_DestroyTexture;
   219     renderer->DestroyRenderer = X11_DestroyRenderer;
   220     renderer->info = X11_RenderDriver.info;
   221     renderer->window = window->id;
   222     renderer->driverdata = data;
   223 
   224     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   225 
   226     if (flags & SDL_RENDERER_SINGLEBUFFER) {
   227         renderer->info.flags |=
   228             (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY);
   229         n = 0;
   230     } else if (flags & SDL_RENDERER_PRESENTFLIP2) {
   231         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   232         n = 2;
   233     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   234         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   235         n = 3;
   236     } else {
   237         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   238         n = 1;
   239     }
   240     for (i = 0; i < n; ++i) {
   241         data->pixmaps[i] =
   242             XCreatePixmap(data->display, data->window, window->w, window->h,
   243                           displaydata->depth);
   244         if (data->pixmaps[i] == None) {
   245             X11_DestroyRenderer(renderer);
   246             SDL_SetError("XCreatePixmap() failed");
   247             return NULL;
   248         }
   249     }
   250     if (n > 0) {
   251         data->drawable = data->pixmaps[0];
   252         data->makedirty = SDL_TRUE;
   253     } else {
   254         data->drawable = data->window;
   255         data->makedirty = SDL_FALSE;
   256     }
   257     data->current_pixmap = 0;
   258 
   259     /* Get the format of the window */
   260     if (!SDL_PixelFormatEnumToMasks
   261         (display->current_mode.format, &bpp, &Rmask, &Gmask, &Bmask,
   262          &Amask)) {
   263         SDL_SetError("Unknown display format");
   264         X11_DestroyRenderer(renderer);
   265         return NULL;
   266     }
   267     SDL_InitFormat(&data->format, bpp, Rmask, Gmask, Bmask, Amask);
   268 
   269     /* Create the drawing context */
   270     gcv.graphics_exposures = False;
   271     data->gc =
   272         XCreateGC(data->display, data->window, GCGraphicsExposures, &gcv);
   273     if (!data->gc) {
   274         X11_DestroyRenderer(renderer);
   275         SDL_SetError("XCreateGC() failed");
   276         return NULL;
   277     }
   278 
   279     return renderer;
   280 }
   281 
   282 static int
   283 X11_DisplayModeChanged(SDL_Renderer * renderer)
   284 {
   285     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   286     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   287     int i, n;
   288 
   289     if (renderer->info.flags & SDL_RENDERER_SINGLEBUFFER) {
   290         n = 0;
   291     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   292         n = 2;
   293     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   294         n = 3;
   295     } else {
   296         n = 1;
   297     }
   298     for (i = 0; i < n; ++i) {
   299         if (data->pixmaps[i] != None) {
   300             XFreePixmap(data->display, data->pixmaps[i]);
   301             data->pixmaps[i] = None;
   302         }
   303     }
   304     for (i = 0; i < n; ++i) {
   305         data->pixmaps[i] =
   306             XCreatePixmap(data->display, data->window, window->w, window->h,
   307                           data->depth);
   308         if (data->pixmaps[i] == None) {
   309             SDL_SetError("XCreatePixmap() failed");
   310             return -1;
   311         }
   312     }
   313     if (n > 0) {
   314         data->drawable = data->pixmaps[0];
   315     }
   316     data->current_pixmap = 0;
   317 
   318     return 0;
   319 }
   320 
   321 static int
   322 X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   323 {
   324     X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
   325     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   326     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   327     X11_TextureData *data;
   328     int pitch_alignmask = ((renderdata->scanline_pad / 8) - 1);
   329 
   330     data = (X11_TextureData *) SDL_calloc(1, sizeof(*data));
   331     if (!data) {
   332         SDL_OutOfMemory();
   333         return -1;
   334     }
   335 
   336     texture->driverdata = data;
   337 
   338     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   339         data->yuv =
   340             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   341         if (!data->yuv) {
   342             return -1;
   343         }
   344         data->format = display->current_mode.format;
   345     } else {
   346         /* The image/pixmap depth must be the same as the window or you
   347            get a BadMatch error when trying to putimage or copyarea.
   348          */
   349         if (texture->format != display->current_mode.format) {
   350             SDL_SetError("Texture format doesn't match window format");
   351             return -1;
   352         }
   353         data->format = texture->format;
   354     }
   355     data->pitch = texture->w * SDL_BYTESPERPIXEL(data->format);
   356     data->pitch = (data->pitch + pitch_alignmask) & ~pitch_alignmask;
   357 
   358     if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) {
   359 #ifndef NO_SHARED_MEMORY
   360         XShmSegmentInfo *shminfo = &data->shminfo;
   361 
   362         shm_error = True;
   363 
   364         if (SDL_X11_HAVE_SHM) {
   365             shminfo->shmid =
   366                 shmget(IPC_PRIVATE, texture->h * data->pitch,
   367                        IPC_CREAT | 0777);
   368             if (shminfo->shmid >= 0) {
   369                 shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
   370                 shminfo->readOnly = False;
   371                 if (shminfo->shmaddr != (char *) -1) {
   372                     shm_error = False;
   373                     X_handler = XSetErrorHandler(shm_errhandler);
   374                     XShmAttach(renderdata->display, shminfo);
   375                     XSync(renderdata->display, False);
   376                     XSetErrorHandler(X_handler);
   377                     if (shm_error) {
   378                         shmdt(shminfo->shmaddr);
   379                     }
   380                 }
   381                 shmctl(shminfo->shmid, IPC_RMID, NULL);
   382             }
   383         }
   384         if (!shm_error) {
   385             data->pixels = shminfo->shmaddr;
   386 
   387             data->image =
   388                 XShmCreateImage(renderdata->display, renderdata->visual,
   389                                 renderdata->depth, ZPixmap, shminfo->shmaddr,
   390                                 shminfo, texture->w, texture->h);
   391             if (!data->image) {
   392                 XShmDetach(renderdata->display, shminfo);
   393                 XSync(renderdata->display, False);
   394                 shmdt(shminfo->shmaddr);
   395                 shm_error = True;
   396             }
   397         }
   398         if (shm_error) {
   399             shminfo->shmaddr = NULL;
   400         }
   401         if (!data->image)
   402 #endif /* not NO_SHARED_MEMORY */
   403         {
   404             data->pixels = SDL_malloc(texture->h * data->pitch);
   405             if (!data->pixels) {
   406                 X11_DestroyTexture(renderer, texture);
   407                 SDL_OutOfMemory();
   408                 return -1;
   409             }
   410 
   411             data->image =
   412                 XCreateImage(renderdata->display, renderdata->visual,
   413                              renderdata->depth, ZPixmap, 0, data->pixels,
   414                              texture->w, texture->h,
   415                              SDL_BYTESPERPIXEL(data->format) * 8,
   416                              data->pitch);
   417             if (!data->image) {
   418                 X11_DestroyTexture(renderer, texture);
   419                 SDL_SetError("XCreateImage() failed");
   420                 return -1;
   421             }
   422         }
   423     } else {
   424         data->pixmap =
   425             XCreatePixmap(renderdata->display, renderdata->window, texture->w,
   426                           texture->h, renderdata->depth);
   427         if (data->pixmap == None) {
   428             X11_DestroyTexture(renderer, texture);
   429             SDL_SetError("XCreatePixmap() failed");
   430             return -1;
   431         }
   432 
   433         data->image =
   434             XCreateImage(renderdata->display, renderdata->visual,
   435                          renderdata->depth, ZPixmap, 0, NULL, texture->w,
   436                          texture->h, SDL_BYTESPERPIXEL(data->format) * 8,
   437                          data->pitch);
   438         if (!data->image) {
   439             X11_DestroyTexture(renderer, texture);
   440             SDL_SetError("XCreateImage() failed");
   441             return -1;
   442         }
   443     }
   444 
   445     return 0;
   446 }
   447 
   448 static int
   449 X11_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   450                        void **pixels, int *pitch)
   451 {
   452     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   453 
   454     if (data->yuv) {
   455         return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
   456     } else {
   457         *pixels = data->pixels;
   458         *pitch = data->pitch;
   459         return 0;
   460     }
   461 }
   462 
   463 static int
   464 X11_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   465 {
   466     switch (texture->blendMode) {
   467     case SDL_BLENDMODE_NONE:
   468         return 0;
   469     default:
   470         SDL_Unsupported();
   471         texture->blendMode = SDL_BLENDMODE_NONE;
   472         return -1;
   473     }
   474 }
   475 
   476 static int
   477 X11_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   478 {
   479     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   480 
   481     switch (texture->scaleMode) {
   482     case SDL_TEXTURESCALEMODE_NONE:
   483         return 0;
   484     case SDL_TEXTURESCALEMODE_FAST:
   485         /* We can sort of fake it for streaming textures */
   486         if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) {
   487             return 0;
   488         }
   489         /* Fall through to unsupported case */
   490     default:
   491         SDL_Unsupported();
   492         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   493         return -1;
   494     }
   495     return 0;
   496 }
   497 
   498 static int
   499 X11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   500                   const SDL_Rect * rect, const void *pixels, int pitch)
   501 {
   502     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   503 
   504     if (data->yuv) {
   505         if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
   506             return -1;
   507         }
   508         UpdateYUVTextureData(texture);
   509         return 0;
   510     } else {
   511         X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
   512 
   513         if (data->pixels) {
   514             Uint8 *src, *dst;
   515             int row;
   516             size_t length;
   517 
   518             src = (Uint8 *) pixels;
   519             dst =
   520                 (Uint8 *) data->pixels + rect->y * data->pitch +
   521                 rect->x * SDL_BYTESPERPIXEL(texture->format);
   522             length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   523             for (row = 0; row < rect->h; ++row) {
   524                 SDL_memcpy(dst, src, length);
   525                 src += pitch;
   526                 dst += data->pitch;
   527             }
   528         } else {
   529             data->image->width = rect->w;
   530             data->image->height = rect->h;
   531             data->image->data = (char *) pixels;
   532             data->image->bytes_per_line = pitch;
   533             XPutImage(renderdata->display, data->pixmap, renderdata->gc,
   534                       data->image, 0, 0, rect->x, rect->y, rect->w, rect->h);
   535         }
   536         return 0;
   537     }
   538 }
   539 
   540 static int
   541 X11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   542                 const SDL_Rect * rect, int markDirty, void **pixels,
   543                 int *pitch)
   544 {
   545     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   546 
   547     if (data->yuv) {
   548         return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
   549                                      pitch);
   550     } else if (data->pixels) {
   551         *pixels =
   552             (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   553                       rect->x * SDL_BYTESPERPIXEL(texture->format));
   554         *pitch = data->pitch;
   555         return 0;
   556     } else {
   557         SDL_SetError("No pixels available");
   558         return -1;
   559     }
   560 }
   561 
   562 static void
   563 X11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   564 {
   565     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   566 
   567     if (data->yuv) {
   568         SDL_SW_UnlockYUVTexture(data->yuv);
   569         UpdateYUVTextureData(texture);
   570     }
   571 }
   572 
   573 static int
   574 X11_SetDrawBlendMode(SDL_Renderer * renderer)
   575 {
   576     switch (renderer->blendMode) {
   577     case SDL_BLENDMODE_NONE:
   578         return 0;
   579     default:
   580         SDL_Unsupported();
   581         renderer->blendMode = SDL_BLENDMODE_NONE;
   582         return -1;
   583     }
   584 }
   585 
   586 static Uint32
   587 renderdrawcolor(SDL_Renderer * renderer, int premult)
   588 {
   589     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   590     Uint8 r = renderer->r;
   591     Uint8 g = renderer->g;
   592     Uint8 b = renderer->b;
   593     Uint8 a = renderer->a;
   594     if (premult)
   595         return SDL_MapRGBA(&data->format, ((int) r * (int) a) / 255,
   596                            ((int) g * (int) a) / 255,
   597                            ((int) b * (int) a) / 255, 255);
   598     else
   599         return SDL_MapRGBA(&data->format, r, g, b, a);
   600 }
   601 
   602 static int
   603 X11_RenderPoints(SDL_Renderer * renderer, const SDL_Point * points, int count)
   604 {
   605     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   606     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   607     unsigned long foreground;
   608     XPoint *xpoints, *xpoint;
   609     int i, xcount;
   610 
   611     if (data->makedirty) {
   612         SDL_Rect rect;
   613 
   614         /* Get the smallest rectangle that contains everything */
   615         rect.x = 0;
   616         rect.y = 0;
   617         rect.w = window->w;
   618         rect.h = window->h;
   619         if (!SDL_EnclosePoints(points, count, &rect, &rect)) {
   620             /* Nothing to draw */
   621             return 0;
   622         }
   623         SDL_AddDirtyRect(&data->dirty, &rect);
   624     }
   625 
   626     foreground = renderdrawcolor(renderer, 1);
   627     XSetForeground(data->display, data->gc, foreground);
   628 
   629     xpoint = xpoints = SDL_stack_alloc(XPoint, count);
   630     xcount = 0;
   631     for (i = 0; i < count; ++i) {
   632         int x = points[i].x;
   633         int y = points[i].y;
   634         if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
   635             continue;
   636         }
   637         xpoint->x = (short)x;
   638         xpoint->y = (short)y;
   639         ++xpoint;
   640         ++xcount;
   641     }
   642     if (xcount > 0) {
   643         XDrawPoints(data->display, data->drawable, data->gc, xpoints, xcount,
   644                     CoordModeOrigin);
   645     }
   646     SDL_stack_free(xpoints);
   647 
   648     return 0;
   649 }
   650 
   651 static int
   652 X11_RenderLines(SDL_Renderer * renderer, const SDL_Point * points, int count)
   653 {
   654     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   655     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   656     SDL_Rect clip, rect;
   657     unsigned long foreground;
   658     XPoint *xpoints, *xpoint;
   659     int i, xcount;
   660     int minx, miny;
   661     int maxx, maxy;
   662 
   663     clip.x = 0;
   664     clip.y = 0;
   665     clip.w = window->w;
   666     clip.h = window->h;
   667 
   668     foreground = renderdrawcolor(renderer, 1);
   669     XSetForeground(data->display, data->gc, foreground);
   670 
   671     xpoint = xpoints = SDL_stack_alloc(XPoint, count);
   672     xcount = 0;
   673     minx = INT_MAX;
   674     miny = INT_MAX;
   675     maxx = INT_MIN;
   676     maxy = INT_MIN;
   677     for (i = 0; i < count; ++i) {
   678         int x = points[i].x;
   679         int y = points[i].y;
   680 
   681         /* If the point is inside the window, add it to the list */
   682         if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
   683             if (x < minx) {
   684                 minx = x;
   685             } else if (x > maxx) {
   686                 maxx = x;
   687             }
   688             if (y < miny) {
   689                 miny = y;
   690             } else if (y > maxy) {
   691                 maxy = y;
   692             }
   693             xpoint->x = (short)x;
   694             xpoint->y = (short)y;
   695             ++xpoint;
   696             ++xcount;
   697             continue;
   698         }
   699 
   700         /* We need to clip the line segments joined by this point */
   701         if (xcount > 0) {
   702             int x1 = xpoint[-1].x;
   703             int y1 = xpoint[-1].y;
   704             int x2 = x;
   705             int y2 = y;
   706             if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) {
   707                 if (x2 < minx) {
   708                     minx = x2;
   709                 } else if (x2 > maxx) {
   710                     maxx = x2;
   711                 }
   712                 if (y2 < miny) {
   713                     miny = y2;
   714                 } else if (y2 > maxy) {
   715                     maxy = y2;
   716                 }
   717                 xpoint->x = (short)x2;
   718                 xpoint->y = (short)y2;
   719                 ++xpoint;
   720                 ++xcount;
   721             }
   722             XDrawLines(data->display, data->drawable, data->gc,
   723                        xpoints, xcount, CoordModeOrigin);
   724             if (xpoints[0].x != x2 || xpoints[0].y != y2) {
   725                 XDrawPoint(data->display, data->drawable, data->gc, x2, y2);
   726             }
   727             if (data->makedirty) {
   728                 SDL_Rect rect;
   729 
   730                 rect.x = minx;
   731                 rect.y = miny;
   732                 rect.w = (maxx - minx) + 1;
   733                 rect.h = (maxy - miny) + 1;
   734                 SDL_AddDirtyRect(&data->dirty, &rect);
   735             }
   736             xpoint = xpoints;
   737             xcount = 0;
   738             minx = INT_MAX;
   739             miny = INT_MAX;
   740             maxx = INT_MIN;
   741             maxy = INT_MIN;
   742         }
   743         if (i < (count-1)) {
   744             int x1 = x;
   745             int y1 = y;
   746             int x2 = points[i+1].x;
   747             int y2 = points[i+1].y;
   748             if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) {
   749                 if (x1 < minx) {
   750                     minx = x1;
   751                 } else if (x1 > maxx) {
   752                     maxx = x1;
   753                 }
   754                 if (y1 < miny) {
   755                     miny = y1;
   756                 } else if (y1 > maxy) {
   757                     maxy = y1;
   758                 }
   759                 xpoint->x = (short)x1;
   760                 xpoint->y = (short)y1;
   761                 ++xpoint;
   762                 ++xcount;
   763             }
   764         }
   765     }
   766     if (xcount > 1) {
   767         int x2 = xpoint[-1].x;
   768         int y2 = xpoint[-1].y;
   769         XDrawLines(data->display, data->drawable, data->gc, xpoints, xcount,
   770                    CoordModeOrigin);
   771         if (xpoints[0].x != x2 || xpoints[0].y != y2) {
   772             XDrawPoint(data->display, data->drawable, data->gc, x2, y2);
   773         }
   774         if (data->makedirty) {
   775             SDL_Rect rect;
   776 
   777             rect.x = minx;
   778             rect.y = miny;
   779             rect.w = (maxx - minx) + 1;
   780             rect.h = (maxy - miny) + 1;
   781             SDL_AddDirtyRect(&data->dirty, &rect);
   782         }
   783     }
   784     SDL_stack_free(xpoints);
   785 
   786     return 0;
   787 }
   788 
   789 static int
   790 X11_RenderRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
   791 {
   792     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   793     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   794     SDL_Rect clip, rect;
   795     unsigned long foreground;
   796     XRectangle *xrects, *xrect;
   797     int i, xcount;
   798 
   799     clip.x = 0;
   800     clip.y = 0;
   801     clip.w = window->w;
   802     clip.h = window->h;
   803 
   804     foreground = renderdrawcolor(renderer, 1);
   805     XSetForeground(data->display, data->gc, foreground);
   806 
   807     xrect = xrects = SDL_stack_alloc(XRectangle, count);
   808     xcount = 0;
   809     for (i = 0; i < count; ++i) {
   810         if (!SDL_IntersectRect(rects[i], &clip, &rect)) {
   811             continue;
   812         }
   813 
   814         xrect->x = (short)rect.x;
   815         xrect->y = (short)rect.y;
   816         xrect->width = (unsigned short)rect.w;
   817         xrect->height = (unsigned short)rect.h;
   818         ++xrect;
   819         ++xcount;
   820 
   821         if (data->makedirty) {
   822             SDL_AddDirtyRect(&data->dirty, &rect);
   823         }
   824     }
   825     if (xcount > 0) {
   826         XFillRectangles(data->display, data->drawable, data->gc,
   827                         xrects, xcount);
   828     }
   829     SDL_stack_free(xpoints);
   830 
   831     return 0;
   832 }
   833 
   834 static int
   835 X11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   836                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   837 {
   838     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   839     X11_TextureData *texturedata = (X11_TextureData *) texture->driverdata;
   840 
   841     if (data->makedirty) {
   842         SDL_AddDirtyRect(&data->dirty, dstrect);
   843     }
   844     if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
   845 #ifndef NO_SHARED_MEMORY
   846         if (texturedata->shminfo.shmaddr) {
   847             XShmPutImage(data->display, data->drawable, data->gc,
   848                          texturedata->image, srcrect->x, srcrect->y,
   849                          dstrect->x, dstrect->y, srcrect->w, srcrect->h,
   850                          False);
   851         } else
   852 #endif
   853         if (texturedata->pixels) {
   854             XPutImage(data->display, data->drawable, data->gc,
   855                       texturedata->image, srcrect->x, srcrect->y, dstrect->x,
   856                       dstrect->y, srcrect->w, srcrect->h);
   857         } else {
   858             XCopyArea(data->display, texturedata->pixmap, data->drawable,
   859                       data->gc, srcrect->x, srcrect->y, dstrect->w,
   860                       dstrect->h, dstrect->x, dstrect->y);
   861         }
   862     } else if (texturedata->yuv
   863                || texture->access == SDL_TEXTUREACCESS_STREAMING) {
   864         SDL_Surface src, dst;
   865         SDL_PixelFormat fmt;
   866         SDL_Rect rect;
   867         XImage *image = texturedata->scaling_image;
   868 
   869         if (!image) {
   870             int depth;
   871             void *pixels;
   872             int pitch;
   873 
   874             pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format);
   875             pixels = SDL_malloc(dstrect->h * pitch);
   876             if (!pixels) {
   877                 SDL_OutOfMemory();
   878                 return -1;
   879             }
   880 
   881             image =
   882                 XCreateImage(data->display, data->visual, data->depth,
   883                              ZPixmap, 0, pixels, dstrect->w, dstrect->h,
   884                              SDL_BYTESPERPIXEL(texturedata->format) * 8,
   885                              pitch);
   886             if (!image) {
   887                 SDL_SetError("XCreateImage() failed");
   888                 return -1;
   889             }
   890             texturedata->scaling_image = image;
   891 
   892         } else if (image->width != dstrect->w || image->height != dstrect->h
   893                    || !image->data) {
   894             image->width = dstrect->w;
   895             image->height = dstrect->h;
   896             image->bytes_per_line =
   897                 image->width * SDL_BYTESPERPIXEL(texturedata->format);
   898             image->data =
   899                 (char *) SDL_realloc(image->data,
   900                                      image->height * image->bytes_per_line);
   901             if (!image->data) {
   902                 SDL_OutOfMemory();
   903                 return -1;
   904             }
   905         }
   906 
   907         /* Set up fake surfaces for SDL_SoftStretch() */
   908         SDL_zero(src);
   909         src.format = &fmt;
   910         src.w = texture->w;
   911         src.h = texture->h;
   912 #ifndef NO_SHARED_MEMORY
   913         if (texturedata->shminfo.shmaddr) {
   914             src.pixels = texturedata->shminfo.shmaddr;
   915         } else
   916 #endif
   917             src.pixels = texturedata->pixels;
   918         src.pitch = texturedata->pitch;
   919 
   920         SDL_zero(dst);
   921         dst.format = &fmt;
   922         dst.w = image->width;
   923         dst.h = image->height;
   924         dst.pixels = image->data;
   925         dst.pitch = image->bytes_per_line;
   926 
   927         fmt.BytesPerPixel = SDL_BYTESPERPIXEL(texturedata->format);
   928 
   929         rect.x = 0;
   930         rect.y = 0;
   931         rect.w = dstrect->w;
   932         rect.h = dstrect->h;
   933         if (SDL_SoftStretch(&src, srcrect, &dst, &rect) < 0) {
   934             return -1;
   935         }
   936         XPutImage(data->display, data->drawable, data->gc, image, 0, 0,
   937                   dstrect->x, dstrect->y, dstrect->w, dstrect->h);
   938     } else {
   939         XCopyArea(data->display, texturedata->pixmap, data->drawable,
   940                   data->gc, srcrect->x, srcrect->y, dstrect->w, dstrect->h,
   941                   srcrect->x, srcrect->y);
   942     }
   943     return 0;
   944 }
   945 
   946 static int
   947 X11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   948                      Uint32 format, void * pixels, int pitch)
   949 {
   950     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   951     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   952     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   953     Uint32 screen_format = display->current_mode.format;
   954     XImage *image;
   955 
   956     image = XGetImage(data->display, data->drawable, rect->x, rect->y,
   957                       rect->w, rect->h, AllPlanes, ZPixmap);
   958 
   959     SDL_ConvertPixels(rect->w, rect->h,
   960                       screen_format, image->data, image->bytes_per_line,
   961                       format, pixels, pitch);
   962 
   963     XDestroyImage(image);
   964     return 0;
   965 }
   966 
   967 static int
   968 X11_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   969                       Uint32 format, const void * pixels, int pitch)
   970 {
   971     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   972     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   973     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   974     Uint32 screen_format = display->current_mode.format;
   975     XImage *image;
   976     void *image_pixels;
   977     int image_pitch;
   978 
   979     image_pitch = rect->w * SDL_BYTESPERPIXEL(screen_format);
   980     image_pixels = SDL_malloc(rect->h * image_pitch);
   981     if (!image_pixels) {
   982         SDL_OutOfMemory();
   983         return -1;
   984     }
   985 
   986     image = XCreateImage(data->display, data->visual,
   987                          data->depth, ZPixmap, 0, image_pixels,
   988                          rect->w, rect->h,
   989                          SDL_BYTESPERPIXEL(screen_format) * 8,
   990                          image_pitch);
   991     if (!image) {
   992         SDL_SetError("XCreateImage() failed");
   993         return -1;
   994     }
   995 
   996     SDL_ConvertPixels(rect->w, rect->h,
   997                       format, pixels, pitch,
   998                       screen_format, image->data, image->bytes_per_line);
   999 
  1000     XPutImage(data->display, data->drawable, data->gc,
  1001               image, 0, 0, rect->x, rect->y, rect->w, rect->h);
  1002 
  1003     image->data = NULL;
  1004     XDestroyImage(image);
  1005 
  1006     SDL_free(image_pixels);
  1007     return 0;
  1008 }
  1009 
  1010 static void
  1011 X11_RenderPresent(SDL_Renderer * renderer)
  1012 {
  1013     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
  1014     SDL_DirtyRect *dirty;
  1015 
  1016     /* Send the data to the display */
  1017     if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) {
  1018         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
  1019             const SDL_Rect *rect = &dirty->rect;
  1020             XCopyArea(data->display, data->drawable, data->window,
  1021                       data->gc, rect->x, rect->y, rect->w, rect->h,
  1022                       rect->x, rect->y);
  1023         }
  1024         SDL_ClearDirtyRects(&data->dirty);
  1025     }
  1026     XSync(data->display, False);
  1027 
  1028     /* Update the flipping chain, if any */
  1029     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
  1030         data->current_pixmap = (data->current_pixmap + 1) % 2;
  1031         data->drawable = data->pixmaps[data->current_pixmap];
  1032     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
  1033         data->current_pixmap = (data->current_pixmap + 1) % 3;
  1034         data->drawable = data->pixmaps[data->current_pixmap];
  1035     }
  1036 }
  1037 
  1038 static void
  1039 X11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1040 {
  1041     X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
  1042     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
  1043 
  1044     if (!data) {
  1045         return;
  1046     }
  1047     if (data->yuv) {
  1048         SDL_SW_DestroyYUVTexture(data->yuv);
  1049     }
  1050     if (data->pixmap != None) {
  1051         XFreePixmap(renderdata->display, data->pixmap);
  1052     }
  1053     if (data->image) {
  1054         data->image->data = NULL;
  1055         XDestroyImage(data->image);
  1056     }
  1057 #ifndef NO_SHARED_MEMORY
  1058     if (data->shminfo.shmaddr) {
  1059         XShmDetach(renderdata->display, &data->shminfo);
  1060         XSync(renderdata->display, False);
  1061         shmdt(data->shminfo.shmaddr);
  1062         data->pixels = NULL;
  1063     }
  1064 #endif
  1065     if (data->scaling_image) {
  1066         SDL_free(data->scaling_image->data);
  1067         data->scaling_image->data = NULL;
  1068         XDestroyImage(data->scaling_image);
  1069     }
  1070     if (data->pixels) {
  1071         SDL_free(data->pixels);
  1072     }
  1073     SDL_free(data);
  1074     texture->driverdata = NULL;
  1075 }
  1076 
  1077 static void
  1078 X11_DestroyRenderer(SDL_Renderer * renderer)
  1079 {
  1080     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
  1081     int i;
  1082 
  1083     if (data) {
  1084         for (i = 0; i < SDL_arraysize(data->pixmaps); ++i) {
  1085             if (data->pixmaps[i] != None) {
  1086                 XFreePixmap(data->display, data->pixmaps[i]);
  1087             }
  1088         }
  1089         if (data->gc) {
  1090             XFreeGC(data->display, data->gc);
  1091         }
  1092         SDL_FreeDirtyRects(&data->dirty);
  1093         SDL_free(data);
  1094     }
  1095     SDL_free(renderer);
  1096 }
  1097 
  1098 #endif /* SDL_VIDEO_RENDER_X11 */
  1099 
  1100 /* vi: set ts=4 sw=4 expandtab: */