src/video/x11/SDL_x11render.c
author Sam Lantinga
Wed, 10 Jun 2009 13:54:13 +0000
changeset 3190 c68d2ca5970f
parent 3066 8cbf68bdf81b
child 3239 ab5aebd50add
permissions -rw-r--r--
Added missing files for OpenGL ES support
     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 "SDL_x11video.h"
    27 #include "../SDL_rect_c.h"
    28 #include "../SDL_pixels_c.h"
    29 #include "../SDL_yuv_sw_c.h"
    30 
    31 /* X11 renderer implementation */
    32 
    33 static SDL_Renderer *X11_CreateRenderer(SDL_Window * window, Uint32 flags);
    34 static int X11_DisplayModeChanged(SDL_Renderer * renderer);
    35 static int X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    36 static int X11_QueryTexturePixels(SDL_Renderer * renderer,
    37                                   SDL_Texture * texture, void **pixels,
    38                                   int *pitch);
    39 static int X11_SetTextureBlendMode(SDL_Renderer * renderer,
    40                                    SDL_Texture * texture);
    41 static int X11_SetTextureScaleMode(SDL_Renderer * renderer,
    42                                    SDL_Texture * texture);
    43 static int X11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    44                              const SDL_Rect * rect, const void *pixels,
    45                              int pitch);
    46 static int X11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    47                            const SDL_Rect * rect, int markDirty,
    48                            void **pixels, int *pitch);
    49 static void X11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    50 static int X11_SetDrawBlendMode(SDL_Renderer * renderer);
    51 static int X11_RenderPoint(SDL_Renderer * renderer, int x, int y);
    52 static int X11_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2,
    53                           int y2);
    54 static int X11_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect);
    55 static int X11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    56                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    57 static void X11_RenderPresent(SDL_Renderer * renderer);
    58 static void X11_DestroyTexture(SDL_Renderer * renderer,
    59                                SDL_Texture * texture);
    60 static void X11_DestroyRenderer(SDL_Renderer * renderer);
    61 
    62 
    63 SDL_RenderDriver X11_RenderDriver = {
    64     X11_CreateRenderer,
    65     {
    66      "x11",
    67      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    68       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    69       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED),
    70      SDL_TEXTUREMODULATE_NONE,
    71      SDL_BLENDMODE_NONE,
    72      SDL_TEXTURESCALEMODE_NONE,
    73      0,
    74      {0},
    75      0,
    76      0}
    77 };
    78 
    79 typedef struct
    80 {
    81     Display *display;
    82     int screen;
    83     Visual *visual;
    84     int depth;
    85     int scanline_pad;
    86     Window window;
    87     Pixmap pixmaps[3];
    88     int current_pixmap;
    89     Drawable drawable;
    90     SDL_PixelFormat format;
    91     GC gc;
    92     SDL_DirtyRectList dirty;
    93     SDL_bool makedirty;
    94 } X11_RenderData;
    95 
    96 typedef struct
    97 {
    98     SDL_SW_YUVTexture *yuv;
    99     Uint32 format;
   100     Pixmap pixmap;
   101     XImage *image;
   102 #ifndef NO_SHARED_MEMORY
   103     /* MIT shared memory extension information */
   104     XShmSegmentInfo shminfo;
   105 #endif
   106     XImage *scaling_image;
   107     void *pixels;
   108     int pitch;
   109 } X11_TextureData;
   110 
   111 #ifndef NO_SHARED_MEMORY
   112 /* Shared memory error handler routine */
   113 static int shm_error;
   114 static int (*X_handler) (Display *, XErrorEvent *) = NULL;
   115 static int
   116 shm_errhandler(Display * d, XErrorEvent * e)
   117 {
   118     if (e->error_code == BadAccess) {
   119         shm_error = True;
   120         return (0);
   121     } else {
   122         return (X_handler(d, e));
   123     }
   124 }
   125 #endif /* ! NO_SHARED_MEMORY */
   126 
   127 static void
   128 UpdateYUVTextureData(SDL_Texture * texture)
   129 {
   130     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   131     SDL_Rect rect;
   132 
   133     rect.x = 0;
   134     rect.y = 0;
   135     rect.w = texture->w;
   136     rect.h = texture->h;
   137     SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
   138                         texture->h, data->pixels, data->pitch);
   139 }
   140 
   141 void
   142 X11_AddRenderDriver(_THIS)
   143 {
   144     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   145     SDL_RendererInfo *info = &X11_RenderDriver.info;
   146     SDL_DisplayMode *mode = &SDL_CurrentDisplay.desktop_mode;
   147 
   148     info->texture_formats[info->num_texture_formats++] = mode->format;
   149     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   150     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   151     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YUY2;
   152     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
   153     info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU;
   154 
   155     SDL_AddRenderDriver(0, &X11_RenderDriver);
   156 }
   157 
   158 SDL_Renderer *
   159 X11_CreateRenderer(SDL_Window * window, Uint32 flags)
   160 {
   161     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   162     SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
   163     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   164     SDL_Renderer *renderer;
   165     SDL_RendererInfo *info;
   166     X11_RenderData *data;
   167     XGCValues gcv;
   168     int i, n;
   169     int bpp;
   170     Uint32 Rmask, Gmask, Bmask, Amask;
   171 
   172     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   173     if (!renderer) {
   174         SDL_OutOfMemory();
   175         return NULL;
   176     }
   177 
   178     data = (X11_RenderData *) SDL_calloc(1, sizeof(*data));
   179     if (!data) {
   180         X11_DestroyRenderer(renderer);
   181         SDL_OutOfMemory();
   182         return NULL;
   183     }
   184     data->display = windowdata->videodata->display;
   185     data->screen = displaydata->screen;
   186     data->visual = displaydata->visual;
   187     data->depth = displaydata->depth;
   188     data->scanline_pad = displaydata->scanline_pad;
   189     data->window = windowdata->window;
   190 
   191     renderer->DisplayModeChanged = X11_DisplayModeChanged;
   192     renderer->CreateTexture = X11_CreateTexture;
   193     renderer->QueryTexturePixels = X11_QueryTexturePixels;
   194     renderer->SetTextureBlendMode = X11_SetTextureBlendMode;
   195     renderer->SetTextureScaleMode = X11_SetTextureScaleMode;
   196     renderer->UpdateTexture = X11_UpdateTexture;
   197     renderer->LockTexture = X11_LockTexture;
   198     renderer->UnlockTexture = X11_UnlockTexture;
   199     renderer->SetDrawBlendMode = X11_SetDrawBlendMode;
   200     renderer->RenderPoint = X11_RenderPoint;
   201     renderer->RenderLine = X11_RenderLine;
   202     renderer->RenderFill = X11_RenderFill;
   203     renderer->RenderCopy = X11_RenderCopy;
   204     renderer->RenderPresent = X11_RenderPresent;
   205     renderer->DestroyTexture = X11_DestroyTexture;
   206     renderer->DestroyRenderer = X11_DestroyRenderer;
   207     renderer->info = X11_RenderDriver.info;
   208     renderer->window = window->id;
   209     renderer->driverdata = data;
   210 
   211     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   212 
   213     if (flags & SDL_RENDERER_SINGLEBUFFER) {
   214         renderer->info.flags |=
   215             (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY);
   216         n = 0;
   217     } else if (flags & SDL_RENDERER_PRESENTFLIP2) {
   218         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   219         n = 2;
   220     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   221         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   222         n = 3;
   223     } else {
   224         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   225         n = 1;
   226     }
   227     for (i = 0; i < n; ++i) {
   228         data->pixmaps[i] =
   229             XCreatePixmap(data->display, data->window, window->w, window->h,
   230                           displaydata->depth);
   231         if (data->pixmaps[i] == None) {
   232             X11_DestroyRenderer(renderer);
   233             SDL_SetError("XCreatePixmap() failed");
   234             return NULL;
   235         }
   236     }
   237     if (n > 0) {
   238         data->drawable = data->pixmaps[0];
   239         data->makedirty = SDL_TRUE;
   240     } else {
   241         data->drawable = data->window;
   242         data->makedirty = SDL_FALSE;
   243     }
   244     data->current_pixmap = 0;
   245 
   246     /* Get the format of the window */
   247     if (!SDL_PixelFormatEnumToMasks
   248         (display->current_mode.format, &bpp, &Rmask, &Gmask, &Bmask,
   249          &Amask)) {
   250         SDL_SetError("Unknown display format");
   251         X11_DestroyRenderer(renderer);
   252         return NULL;
   253     }
   254     SDL_InitFormat(&data->format, bpp, Rmask, Gmask, Bmask, Amask);
   255 
   256     /* Create the drawing context */
   257     gcv.graphics_exposures = False;
   258     data->gc =
   259         XCreateGC(data->display, data->window, GCGraphicsExposures, &gcv);
   260     if (!data->gc) {
   261         X11_DestroyRenderer(renderer);
   262         SDL_SetError("XCreateGC() failed");
   263         return NULL;
   264     }
   265 
   266     return renderer;
   267 }
   268 
   269 static int
   270 X11_DisplayModeChanged(SDL_Renderer * renderer)
   271 {
   272     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   273     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   274     int i, n;
   275 
   276     if (renderer->info.flags & SDL_RENDERER_SINGLEBUFFER) {
   277         n = 0;
   278     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   279         n = 2;
   280     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   281         n = 3;
   282     } else {
   283         n = 1;
   284     }
   285     for (i = 0; i < n; ++i) {
   286         if (data->pixmaps[i] != None) {
   287             XFreePixmap(data->display, data->pixmaps[i]);
   288             data->pixmaps[i] = None;
   289         }
   290     }
   291     for (i = 0; i < n; ++i) {
   292         data->pixmaps[i] =
   293             XCreatePixmap(data->display, data->window, window->w, window->h,
   294                           data->depth);
   295         if (data->pixmaps[i] == None) {
   296             SDL_SetError("XCreatePixmap() failed");
   297             return -1;
   298         }
   299     }
   300     if (n > 0) {
   301         data->drawable = data->pixmaps[0];
   302     }
   303     data->current_pixmap = 0;
   304 
   305     return 0;
   306 }
   307 
   308 static int
   309 X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   310 {
   311     X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
   312     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   313     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   314     X11_TextureData *data;
   315     int pitch_alignmask = ((renderdata->scanline_pad / 8) - 1);
   316 
   317     data = (X11_TextureData *) SDL_calloc(1, sizeof(*data));
   318     if (!data) {
   319         SDL_OutOfMemory();
   320         return -1;
   321     }
   322 
   323     texture->driverdata = data;
   324 
   325     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
   326         data->yuv =
   327             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   328         if (!data->yuv) {
   329             return -1;
   330         }
   331         data->format = display->current_mode.format;
   332     } else {
   333         /* The image/pixmap depth must be the same as the window or you
   334            get a BadMatch error when trying to putimage or copyarea.
   335          */
   336         if (texture->format != display->current_mode.format) {
   337             SDL_SetError("Texture format doesn't match window format");
   338             return -1;
   339         }
   340         data->format = texture->format;
   341     }
   342     data->pitch = texture->w * SDL_BYTESPERPIXEL(data->format);
   343     data->pitch = (data->pitch + pitch_alignmask) & ~pitch_alignmask;
   344 
   345     if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) {
   346 #ifndef NO_SHARED_MEMORY
   347         XShmSegmentInfo *shminfo = &data->shminfo;
   348 
   349         shm_error = True;
   350 
   351         if (SDL_X11_HAVE_SHM) {
   352             shminfo->shmid =
   353                 shmget(IPC_PRIVATE, texture->h * data->pitch,
   354                        IPC_CREAT | 0777);
   355             if (shminfo->shmid >= 0) {
   356                 shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
   357                 shminfo->readOnly = False;
   358                 if (shminfo->shmaddr != (char *) -1) {
   359                     shm_error = False;
   360                     X_handler = XSetErrorHandler(shm_errhandler);
   361                     XShmAttach(renderdata->display, shminfo);
   362                     XSync(renderdata->display, True);
   363                     XSetErrorHandler(X_handler);
   364                     if (shm_error) {
   365                         shmdt(shminfo->shmaddr);
   366                     }
   367                 }
   368                 shmctl(shminfo->shmid, IPC_RMID, NULL);
   369             }
   370         }
   371         if (!shm_error) {
   372             data->pixels = shminfo->shmaddr;
   373 
   374             data->image =
   375                 XShmCreateImage(renderdata->display, renderdata->visual,
   376                                 renderdata->depth, ZPixmap, shminfo->shmaddr,
   377                                 shminfo, texture->w, texture->h);
   378             if (!data->image) {
   379                 XShmDetach(renderdata->display, shminfo);
   380                 XSync(renderdata->display, False);
   381                 shmdt(shminfo->shmaddr);
   382                 shm_error = True;
   383             }
   384         }
   385         if (shm_error) {
   386             shminfo->shmaddr = NULL;
   387         }
   388         if (!data->image)
   389 #endif /* not NO_SHARED_MEMORY */
   390         {
   391             data->pixels = SDL_malloc(texture->h * data->pitch);
   392             if (!data->pixels) {
   393                 X11_DestroyTexture(renderer, texture);
   394                 SDL_OutOfMemory();
   395                 return -1;
   396             }
   397 
   398             data->image =
   399                 XCreateImage(renderdata->display, renderdata->visual,
   400                              renderdata->depth, ZPixmap, 0, data->pixels,
   401                              texture->w, texture->h,
   402                              SDL_BYTESPERPIXEL(data->format) * 8,
   403                              data->pitch);
   404             if (!data->image) {
   405                 X11_DestroyTexture(renderer, texture);
   406                 SDL_SetError("XCreateImage() failed");
   407                 return -1;
   408             }
   409         }
   410     } else {
   411         data->pixmap =
   412             XCreatePixmap(renderdata->display, renderdata->window, texture->w,
   413                           texture->h, renderdata->depth);
   414         if (data->pixmap == None) {
   415             X11_DestroyTexture(renderer, texture);
   416             SDL_SetError("XCreatePixmap() failed");
   417             return -1;
   418         }
   419 
   420         data->image =
   421             XCreateImage(renderdata->display, renderdata->visual,
   422                          renderdata->depth, ZPixmap, 0, NULL, texture->w,
   423                          texture->h, SDL_BYTESPERPIXEL(data->format) * 8,
   424                          data->pitch);
   425         if (!data->image) {
   426             X11_DestroyTexture(renderer, texture);
   427             SDL_SetError("XCreateImage() failed");
   428             return -1;
   429         }
   430     }
   431 
   432     return 0;
   433 }
   434 
   435 static int
   436 X11_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   437                        void **pixels, int *pitch)
   438 {
   439     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   440 
   441     if (data->yuv) {
   442         return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
   443     } else {
   444         *pixels = data->pixels;
   445         *pitch = data->pitch;
   446         return 0;
   447     }
   448 }
   449 
   450 static int
   451 X11_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   452 {
   453     switch (texture->blendMode) {
   454     case SDL_BLENDMODE_NONE:
   455         return 0;
   456     default:
   457         SDL_Unsupported();
   458         texture->blendMode = SDL_BLENDMODE_NONE;
   459         return -1;
   460     }
   461 }
   462 
   463 static int
   464 X11_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   465 {
   466     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   467 
   468     switch (texture->scaleMode) {
   469     case SDL_TEXTURESCALEMODE_NONE:
   470         return 0;
   471     case SDL_TEXTURESCALEMODE_FAST:
   472         /* We can sort of fake it for streaming textures */
   473         if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) {
   474             return 0;
   475         }
   476         /* Fall through to unsupported case */
   477     default:
   478         SDL_Unsupported();
   479         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   480         return -1;
   481     }
   482     return 0;
   483 }
   484 
   485 static int
   486 X11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   487                   const SDL_Rect * rect, const void *pixels, int pitch)
   488 {
   489     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   490 
   491     if (data->yuv) {
   492         if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
   493             return -1;
   494         }
   495         UpdateYUVTextureData(texture);
   496         return 0;
   497     } else {
   498         X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
   499 
   500         if (data->pixels) {
   501             Uint8 *src, *dst;
   502             int row;
   503             size_t length;
   504 
   505             src = (Uint8 *) pixels;
   506             dst =
   507                 (Uint8 *) data->pixels + rect->y * data->pitch +
   508                 rect->x * SDL_BYTESPERPIXEL(texture->format);
   509             length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   510             for (row = 0; row < rect->h; ++row) {
   511                 SDL_memcpy(dst, src, length);
   512                 src += pitch;
   513                 dst += data->pitch;
   514             }
   515         } else {
   516             data->image->width = rect->w;
   517             data->image->height = rect->h;
   518             data->image->data = (char *) pixels;
   519             data->image->bytes_per_line = pitch;
   520             XPutImage(renderdata->display, data->pixmap, renderdata->gc,
   521                       data->image, 0, 0, rect->x, rect->y, rect->w, rect->h);
   522         }
   523         return 0;
   524     }
   525 }
   526 
   527 static int
   528 X11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   529                 const SDL_Rect * rect, int markDirty, void **pixels,
   530                 int *pitch)
   531 {
   532     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   533 
   534     if (data->yuv) {
   535         return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
   536                                      pitch);
   537     } else if (data->pixels) {
   538         *pixels =
   539             (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   540                       rect->x * SDL_BYTESPERPIXEL(texture->format));
   541         *pitch = data->pitch;
   542         return 0;
   543     } else {
   544         SDL_SetError("No pixels available");
   545         return -1;
   546     }
   547 }
   548 
   549 static void
   550 X11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   551 {
   552     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   553 
   554     if (data->yuv) {
   555         SDL_SW_UnlockYUVTexture(data->yuv);
   556         UpdateYUVTextureData(texture);
   557     }
   558 }
   559 
   560 static int
   561 X11_SetDrawBlendMode(SDL_Renderer * renderer)
   562 {
   563     switch (renderer->blendMode) {
   564     case SDL_BLENDMODE_NONE:
   565         return 0;
   566     default:
   567         SDL_Unsupported();
   568         renderer->blendMode = SDL_BLENDMODE_NONE;
   569         return -1;
   570     }
   571 }
   572 
   573 static Uint32
   574 renderdrawcolor(SDL_Renderer * renderer, int premult)
   575 {
   576     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   577     Uint8 r = renderer->r;
   578     Uint8 g = renderer->g;
   579     Uint8 b = renderer->b;
   580     Uint8 a = renderer->a;
   581     if (premult)
   582         return SDL_MapRGBA(&data->format, ((int) r * (int) a) / 255,
   583                            ((int) g * (int) a) / 255,
   584                            ((int) b * (int) a) / 255, 255);
   585     else
   586         return SDL_MapRGBA(&data->format, r, g, b, a);
   587 }
   588 
   589 static int
   590 X11_RenderPoint(SDL_Renderer * renderer, int x, int y)
   591 {
   592     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   593     unsigned long foreground;
   594 
   595     if (data->makedirty) {
   596         SDL_Rect rect;
   597 
   598         rect.x = x;
   599         rect.y = y;
   600         rect.w = 1;
   601         rect.h = 1;
   602         SDL_AddDirtyRect(&data->dirty, &rect);
   603     }
   604 
   605     foreground = renderdrawcolor(renderer, 1);
   606     XSetForeground(data->display, data->gc, foreground);
   607     XDrawPoint(data->display, data->drawable, data->gc, x, y);
   608     return 0;
   609 }
   610 
   611 static int
   612 X11_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
   613 {
   614     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   615     unsigned long foreground;
   616 
   617     if (data->makedirty) {
   618         SDL_Rect rect;
   619 
   620         if (x1 < x2) {
   621             rect.x = x1;
   622             rect.w = (x2 - x1) + 1;
   623         } else {
   624             rect.x = x2;
   625             rect.w = (x1 - x2) + 1;
   626         }
   627         if (y1 < y2) {
   628             rect.y = y1;
   629             rect.h = (y2 - y1) + 1;
   630         } else {
   631             rect.y = y2;
   632             rect.h = (y1 - y2) + 1;
   633         }
   634         SDL_AddDirtyRect(&data->dirty, &rect);
   635     }
   636 
   637     foreground = renderdrawcolor(renderer, 1);
   638     XSetForeground(data->display, data->gc, foreground);
   639     XDrawLine(data->display, data->drawable, data->gc, x1, y1, x2, y2);
   640     return 0;
   641 }
   642 
   643 static int
   644 X11_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect)
   645 {
   646     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   647     unsigned long foreground;
   648 
   649     if (data->makedirty) {
   650         SDL_AddDirtyRect(&data->dirty, rect);
   651     }
   652 
   653     foreground = renderdrawcolor(renderer, 1);
   654     XSetForeground(data->display, data->gc, foreground);
   655     XFillRectangle(data->display, data->drawable, data->gc, rect->x, rect->y,
   656                    rect->w, rect->h);
   657     return 0;
   658 }
   659 
   660 static int
   661 X11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   662                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   663 {
   664     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   665     X11_TextureData *texturedata = (X11_TextureData *) texture->driverdata;
   666 
   667     if (data->makedirty) {
   668         SDL_AddDirtyRect(&data->dirty, dstrect);
   669     }
   670     if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
   671 #ifndef NO_SHARED_MEMORY
   672         if (texturedata->shminfo.shmaddr) {
   673             XShmPutImage(data->display, data->drawable, data->gc,
   674                          texturedata->image, srcrect->x, srcrect->y,
   675                          dstrect->x, dstrect->y, srcrect->w, srcrect->h,
   676                          False);
   677         } else
   678 #endif
   679         if (texturedata->pixels) {
   680             XPutImage(data->display, data->drawable, data->gc,
   681                       texturedata->image, srcrect->x, srcrect->y, dstrect->x,
   682                       dstrect->y, srcrect->w, srcrect->h);
   683         } else {
   684             XCopyArea(data->display, texturedata->pixmap, data->drawable,
   685                       data->gc, srcrect->x, srcrect->y, dstrect->w,
   686                       dstrect->h, dstrect->x, dstrect->y);
   687         }
   688     } else if (texturedata->yuv
   689                || texture->access == SDL_TEXTUREACCESS_STREAMING) {
   690         SDL_Surface src, dst;
   691         SDL_PixelFormat fmt;
   692         SDL_Rect rect;
   693         XImage *image = texturedata->scaling_image;
   694 
   695         if (!image) {
   696             int depth;
   697             void *pixels;
   698             int pitch;
   699 
   700             pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format);
   701             pixels = SDL_malloc(dstrect->h * pitch);
   702             if (!pixels) {
   703                 SDL_OutOfMemory();
   704                 return -1;
   705             }
   706 
   707             image =
   708                 XCreateImage(data->display, data->visual, data->depth,
   709                              ZPixmap, 0, pixels, dstrect->w, dstrect->h,
   710                              SDL_BYTESPERPIXEL(texturedata->format) * 8,
   711                              pitch);
   712             if (!image) {
   713                 SDL_SetError("XCreateImage() failed");
   714                 return -1;
   715             }
   716             texturedata->scaling_image = image;
   717 
   718         } else if (image->width != dstrect->w || image->height != dstrect->h
   719                    || !image->data) {
   720             image->width = dstrect->w;
   721             image->height = dstrect->h;
   722             image->bytes_per_line =
   723                 image->width * SDL_BYTESPERPIXEL(texturedata->format);
   724             image->data =
   725                 (char *) SDL_realloc(image->data,
   726                                      image->height * image->bytes_per_line);
   727             if (!image->data) {
   728                 SDL_OutOfMemory();
   729                 return -1;
   730             }
   731         }
   732 
   733         /* Set up fake surfaces for SDL_SoftStretch() */
   734         SDL_zero(src);
   735         src.format = &fmt;
   736         src.w = texture->w;
   737         src.h = texture->h;
   738 #ifndef NO_SHARED_MEMORY
   739         if (texturedata->shminfo.shmaddr) {
   740             src.pixels = texturedata->shminfo.shmaddr;
   741         } else
   742 #endif
   743             src.pixels = texturedata->pixels;
   744         src.pitch = texturedata->pitch;
   745 
   746         SDL_zero(dst);
   747         dst.format = &fmt;
   748         dst.w = image->width;
   749         dst.h = image->height;
   750         dst.pixels = image->data;
   751         dst.pitch = image->bytes_per_line;
   752 
   753         fmt.BytesPerPixel = SDL_BYTESPERPIXEL(texturedata->format);
   754 
   755         rect.x = 0;
   756         rect.y = 0;
   757         rect.w = dstrect->w;
   758         rect.h = dstrect->h;
   759         if (SDL_SoftStretch(&src, srcrect, &dst, &rect) < 0) {
   760             return -1;
   761         }
   762         XPutImage(data->display, data->drawable, data->gc, image, 0, 0,
   763                   dstrect->x, dstrect->y, dstrect->w, dstrect->h);
   764     } else {
   765         XCopyArea(data->display, texturedata->pixmap, data->drawable,
   766                   data->gc, srcrect->x, srcrect->y, dstrect->w, dstrect->h,
   767                   srcrect->x, srcrect->y);
   768     }
   769     return 0;
   770 }
   771 
   772 static void
   773 X11_RenderPresent(SDL_Renderer * renderer)
   774 {
   775     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   776     SDL_DirtyRect *dirty;
   777 
   778     /* Send the data to the display */
   779     if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) {
   780         for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
   781             const SDL_Rect *rect = &dirty->rect;
   782             XCopyArea(data->display, data->drawable, data->window,
   783                       data->gc, rect->x, rect->y, rect->w, rect->h,
   784                       rect->x, rect->y);
   785         }
   786         SDL_ClearDirtyRects(&data->dirty);
   787     }
   788     XSync(data->display, False);
   789 
   790     /* Update the flipping chain, if any */
   791     if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
   792         data->current_pixmap = (data->current_pixmap + 1) % 2;
   793         data->drawable = data->pixmaps[data->current_pixmap];
   794     } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
   795         data->current_pixmap = (data->current_pixmap + 1) % 3;
   796         data->drawable = data->pixmaps[data->current_pixmap];
   797     }
   798 }
   799 
   800 static void
   801 X11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   802 {
   803     X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata;
   804     X11_TextureData *data = (X11_TextureData *) texture->driverdata;
   805 
   806     if (!data) {
   807         return;
   808     }
   809     if (data->yuv) {
   810         SDL_SW_DestroyYUVTexture(data->yuv);
   811     }
   812     if (data->pixmap != None) {
   813         XFreePixmap(renderdata->display, data->pixmap);
   814     }
   815     if (data->image) {
   816         data->image->data = NULL;
   817         XDestroyImage(data->image);
   818     }
   819 #ifndef NO_SHARED_MEMORY
   820     if (data->shminfo.shmaddr) {
   821         XShmDetach(renderdata->display, &data->shminfo);
   822         XSync(renderdata->display, False);
   823         shmdt(data->shminfo.shmaddr);
   824         data->pixels = NULL;
   825     }
   826 #endif
   827     if (data->scaling_image) {
   828         SDL_free(data->scaling_image->data);
   829         data->scaling_image->data = NULL;
   830         XDestroyImage(data->scaling_image);
   831     }
   832     if (data->pixels) {
   833         SDL_free(data->pixels);
   834     }
   835     SDL_free(data);
   836     texture->driverdata = NULL;
   837 }
   838 
   839 static void
   840 X11_DestroyRenderer(SDL_Renderer * renderer)
   841 {
   842     X11_RenderData *data = (X11_RenderData *) renderer->driverdata;
   843     int i;
   844 
   845     if (data) {
   846         for (i = 0; i < SDL_arraysize(data->pixmaps); ++i) {
   847             if (data->pixmaps[i] != None) {
   848                 XFreePixmap(data->display, data->pixmaps[i]);
   849             }
   850         }
   851         if (data->gc) {
   852             XFreeGC(data->display, data->gc);
   853         }
   854         SDL_FreeDirtyRects(&data->dirty);
   855         SDL_free(data);
   856     }
   857     SDL_free(renderer);
   858 }
   859 
   860 #endif /* SDL_VIDEO_RENDER_X11 */
   861 
   862 /* vi: set ts=4 sw=4 expandtab: */