Mercurial > sdl-ios-xcode
diff src/video/x11/SDL_x11render.c @ 4618:844b5ef4b149
Merged Sunny's XRender changes from SDL-gsoc2010_xrender
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 28 Jul 2010 00:54:23 -0700 |
parents | 791b3256fb22 cfbb1ff4b8ec |
children | b9a205e6369f |
line wrap: on
line diff
--- a/src/video/x11/SDL_x11render.c Tue Jul 27 21:31:28 2010 -0700 +++ b/src/video/x11/SDL_x11render.c Wed Jul 28 00:54:23 2010 -0700 @@ -1,4 +1,5 @@ /* + SDL - Simple DirectMedia Layer Copyright (C) 1997-2010 Sam Lantinga @@ -39,6 +40,8 @@ static int X11_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch); +static int X11_SetTextureRGBAMod(SDL_Renderer * renderer, + SDL_Texture * texture); static int X11_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture); static int X11_SetTextureScaleMode(SDL_Renderer * renderer, @@ -96,6 +99,25 @@ int scanline_pad; Window xwindow; Pixmap pixmaps[3]; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + Pixmap stencil; + Pixmap brush; + Picture brush_pict; + Picture xwindow_pict; + Picture pixmap_picts[3]; + Picture drawable_pict; + Picture stencil_pict; + int blend_op; + XRenderPictFormat *xwindow_pict_fmt; + XRenderPictFormat *drawable_pict_fmt; + GC stencil_gc; + SDL_bool use_xrender; +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + SDL_bool use_xdamage; + Damage stencil_damage; + XserverRegion stencil_parts; +#endif +#endif int current_pixmap; Drawable drawable; SDL_PixelFormat format; @@ -109,6 +131,17 @@ SDL_SW_YUVTexture *yuv; Uint32 format; Pixmap pixmap; + int depth; + Visual *visual; + GC gc; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + Picture picture; + Pixmap modulated_pixmap; + Picture modulated_picture; + XRenderPictFormat* picture_fmt; + int blend_op; + const char* filter; +#endif XImage *image; #ifndef NO_SHARED_MEMORY /* MIT shared memory extension information */ @@ -149,11 +182,109 @@ texture->h, data->pixels, data->pitch); } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER +static SDL_bool +CheckXRender(Display *display, int *major, int *minor) { + const char *env; + + *major = *minor = 0; + + env = SDL_getenv("SDL_VIDEO_X11_XRENDER"); + + if (env && !SDL_atoi(env)) { + return SDL_FALSE; + } + + if (!SDL_X11_HAVE_XRENDER) { + return SDL_FALSE; + } + + if (!XRenderQueryVersion(display, major, minor)) { + return SDL_FALSE; + } + + return SDL_TRUE; +} +#endif + +#ifdef SDL_VIDEO_DRIVER_X11_XFIXES +static SDL_bool +CheckXFixes(Display *display, int *major, int *minor) { + const char *env; + + *major = *minor = 0; + + env = SDL_getenv("SDL_VIDEO_X11_XFIXES"); + + if (env && !SDL_atoi(env)) { + return SDL_FALSE; + } + + if (!SDL_X11_HAVE_XFIXES) { + return SDL_FALSE; + } + + if (!XFixesQueryVersion(display, major, minor)) { + return SDL_FALSE; + } + + return SDL_TRUE; +} +#endif + +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE +static SDL_bool +CheckXDamage(Display *display, int *major, int *minor) { + const char *env; + + *major = *minor = 0; + + env = SDL_getenv("SDL_VIDEO_X11_XDAMAGE"); + + if (env && !SDL_atoi(env)) { + return SDL_FALSE; + } + + if (!SDL_X11_HAVE_XDAMAGE) { + return SDL_FALSE; + } + + if (!XDamageQueryVersion(display, major, minor)) { + return SDL_FALSE; + } + + return SDL_TRUE; +} +#endif + +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER +static Uint32 +XRenderPictFormatToSDLPixelFormatEnum(XRenderPictFormat *pict_format) { + if (pict_format->type != PictTypeDirect) { + SDL_SetError("Indexed pict formats not supported ATM"); + return 0; + } + Uint32 Amask, Rmask, Gmask, Bmask; + int bpp; + + Rmask = pict_format->direct.redMask << pict_format->direct.red; + Gmask = pict_format->direct.greenMask << pict_format->direct.green; + Bmask = pict_format->direct.blueMask << pict_format->direct.blue; + Amask = pict_format->direct.alphaMask << pict_format->direct.alpha; + bpp = pict_format->depth; + + Uint32 format; + format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); + return format; +} +#endif + void X11_AddRenderDriver(_THIS) { SDL_RendererInfo *info = &X11_RenderDriver.info; SDL_DisplayMode *mode = &SDL_CurrentDisplay->desktop_mode; + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; int i; info->texture_formats[info->num_texture_formats++] = mode->format; @@ -163,6 +294,34 @@ info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY; info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + int major, minor; + if (CheckXRender(data->display, &major, &minor)) { + XRenderPictFormat templ; + templ.type = PictTypeDirect; + XRenderPictFormat *pict_format; + Uint32 format; + int i = 0; + while (info->num_texture_formats < 50) { + pict_format = + XRenderFindFormat(data->display, PictFormatType, &templ, i++); + if (pict_format) { + format = XRenderPictFormatToSDLPixelFormatEnum(pict_format); + if (format != SDL_PIXELTYPE_UNKNOWN) { + info->texture_formats[info->num_texture_formats++] = format; + } + } + else + break; + } + info->blend_modes |= (SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | + SDL_BLENDMODE_MOD | SDL_BLENDMODE_MASK); + info->scale_modes |= (SDL_TEXTURESCALEMODE_FAST | SDL_TEXTURESCALEMODE_SLOW | + SDL_TEXTURESCALEMODE_BEST); + info->mod_modes |= (SDL_TEXTUREMODULATE_COLOR | SDL_TEXTUREMODULATE_ALPHA); + } +#endif + for (i = 0; i < _this->num_displays; ++i) { SDL_AddRenderDriver(&_this->displays[i], &X11_RenderDriver); } @@ -177,6 +336,7 @@ SDL_Renderer *renderer; X11_RenderData *data; XGCValues gcv; + gcv.graphics_exposures = False; int i, n; int bpp; Uint32 Rmask, Gmask, Bmask, Amask; @@ -199,10 +359,12 @@ data->depth = displaydata->depth; data->scanline_pad = displaydata->scanline_pad; data->xwindow = windowdata->xwindow; - + renderer->DisplayModeChanged = X11_DisplayModeChanged; renderer->CreateTexture = X11_CreateTexture; renderer->QueryTexturePixels = X11_QueryTexturePixels; + renderer->SetTextureAlphaMod = X11_SetTextureRGBAMod; + renderer->SetTextureColorMod = X11_SetTextureRGBAMod; renderer->SetTextureBlendMode = X11_SetTextureBlendMode; renderer->SetTextureScaleMode = X11_SetTextureScaleMode; renderer->UpdateTexture = X11_UpdateTexture; @@ -225,6 +387,82 @@ renderer->info.flags = SDL_RENDERER_ACCELERATED; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + int major, minor; + data->use_xrender = CheckXRender(data->display, &major, &minor); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (CheckXDamage(data->display, &major, &minor)) { + if (CheckXFixes(data->display, &major, &minor)) { + if (major >= 2) + data->use_xdamage = SDL_TRUE; + } + } +#endif + if (data->use_xrender) { + /* Find the PictFormat from the visual. + * Should be an RGB PictFormat most of the time. */ + data->xwindow_pict_fmt = XRenderFindVisualFormat(data->display, + data->visual); + if (!data->xwindow_pict_fmt) { + SDL_SetError("XRenderFindVisualFormat() failed"); + return NULL; + } + data->xwindow_pict = XRenderCreatePicture(data->display, + data->xwindow, + data->xwindow_pict_fmt, + 0, NULL); + if (!data->xwindow_pict) { + SDL_SetError("XRenderCreatePicture() failed"); + return NULL; + } + // FIXME: Clear the window. Is this required? + XRenderComposite(data->display, + PictOpClear, + data->xwindow_pict, + None, + data->xwindow_pict, + 0, 0, + 0, 0, + 0, 0, + window->w, window->h); + /* Create a clip mask that is used for rendering primitives. */ + data->stencil = XCreatePixmap(data->display, data->xwindow, + window->w, window->h, 32); + + /* Create the GC for the clip mask. */ + data->stencil_gc = XCreateGC(data->display, data->stencil, + GCGraphicsExposures, &gcv); + XSetBackground(data->display, data->stencil_gc, 0); + XSetForeground(data->display, data->stencil_gc, 0); + XFillRectangle(data->display, data->stencil, data->stencil_gc, + 0, 0, window->w, window->h); + XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF); + data->stencil_pict = + XRenderCreatePicture(data->display, data->stencil, + XRenderFindStandardFormat(data->display, + PictStandardARGB32), + 0, NULL); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) { + data->stencil_damage = + XDamageCreate(data->display, data->stencil, XDamageReportNonEmpty); + XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts); + } +#endif + data->brush = + XCreatePixmap(data->display, data->xwindow, 1, 1, 32); + XRenderPictureAttributes brush_attr; + brush_attr.repeat = RepeatNormal; + data->brush_pict = + XRenderCreatePicture(data->display, data->brush, + XRenderFindStandardFormat(data->display, + PictStandardARGB32), + CPRepeat, &brush_attr); + // Set the default blending mode. + renderer->blendMode = SDL_BLENDMODE_BLEND; + data->blend_op = PictOpOver; + } +#endif if (flags & SDL_RENDERER_SINGLEBUFFER) { renderer->info.flags |= (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY); @@ -239,39 +477,110 @@ renderer->info.flags |= SDL_RENDERER_PRESENTCOPY; n = 1; } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + if (n > 0) + data->drawable_pict_fmt = + XRenderFindStandardFormat(data->display, PictStandardARGB32); + else + data->drawable_pict_fmt = data->xwindow_pict_fmt; + } +#endif for (i = 0; i < n; ++i) { - data->pixmaps[i] = - XCreatePixmap(data->display, data->xwindow, window->w, window->h, - displaydata->depth); +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + data->pixmaps[i] = XCreatePixmap(data->display, + data->xwindow, + window->w, + window->h, + 32); + } + else +#endif + { + data->pixmaps[i] = + XCreatePixmap(data->display, data->xwindow, window->w, window->h, + displaydata->depth); + } if (data->pixmaps[i] == None) { X11_DestroyRenderer(renderer); SDL_SetError("XCreatePixmap() failed"); return NULL; } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + /* Create xrender pictures for each of the pixmaps + * and clear the pixmaps. */ + data->pixmap_picts[i] = + XRenderCreatePicture(data->display, + data->pixmaps[i], + XRenderFindStandardFormat(data->display, + PictStandardARGB32), + 0, None); + if (!data->pixmap_picts[i]) { + SDL_SetError("XRenderCreatePicture() failed"); + return NULL; + } + + XRenderComposite(data->display, + PictOpClear, + data->pixmap_picts[i], + None, + data->pixmap_picts[i], + 0, 0, + 0, 0, + 0, 0, + window->w, window->h); + } +#endif } if (n > 0) { data->drawable = data->pixmaps[0]; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if(data->use_xrender == SDL_TRUE) + data->drawable_pict = data->pixmap_picts[0]; +#endif data->makedirty = SDL_TRUE; } else { data->drawable = data->xwindow; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if(data->use_xrender == SDL_TRUE) + data->drawable_pict = data->xwindow_pict; +#endif data->makedirty = SDL_FALSE; } data->current_pixmap = 0; - /* Get the format of the window */ - if (!SDL_PixelFormatEnumToMasks - (display->current_mode.format, &bpp, &Rmask, &Gmask, &Bmask, - &Amask)) { - SDL_SetError("Unknown display format"); - X11_DestroyRenderer(renderer); - return NULL; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + bpp = data->drawable_pict_fmt->depth; + Rmask = ((data->drawable_pict_fmt->direct.redMask) + << (data->drawable_pict_fmt->direct.red)); + Gmask = ((data->drawable_pict_fmt->direct.greenMask) + << (data->drawable_pict_fmt->direct.green)); + Bmask = ((data->drawable_pict_fmt->direct.blueMask) + << (data->drawable_pict_fmt->direct.blue)); + Amask = ((data->drawable_pict_fmt->direct.alphaMask) + << (data->drawable_pict_fmt->direct.alpha)); + } + else +#endif + { + /* Get the format of the window */ + if (!SDL_PixelFormatEnumToMasks + (display->current_mode.format, &bpp, &Rmask, &Gmask, &Bmask, + &Amask)) { + SDL_SetError("Unknown display format"); + X11_DestroyRenderer(renderer); + return NULL; + } } SDL_InitFormat(&data->format, bpp, Rmask, Gmask, Bmask, Amask); /* Create the drawing context */ gcv.graphics_exposures = False; data->gc = - XCreateGC(data->display, data->xwindow, GCGraphicsExposures, &gcv); + XCreateGC(data->display, data->drawable, GCGraphicsExposures, &gcv); if (!data->gc) { X11_DestroyRenderer(renderer); SDL_SetError("XCreateGC() failed"); @@ -288,6 +597,47 @@ SDL_Window *window = renderer->window; int i, n; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + XRenderFreePicture(data->display, data->xwindow_pict); + + data->xwindow_pict_fmt = + XRenderFindVisualFormat(data->display, data->visual); + data->xwindow_pict = + XRenderCreatePicture(data->display, data->xwindow, + data->xwindow_pict_fmt, 0, NULL); + + XRenderComposite(data->display, + PictOpClear, + data->xwindow_pict, + None, + data->xwindow_pict, + 0, 0, + 0, 0, + 0, 0, + window->w, window->h); + + XFreePixmap(data->display, data->stencil); + /* Create a clip mask that is used for rendering primitives. */ + data->stencil = XCreatePixmap(data->display, data->xwindow, + window->w, window->h, 32); + + XRenderFreePicture(data->display, data->stencil_pict); + data->stencil_pict = + XRenderCreatePicture(data->display, data->stencil, + XRenderFindStandardFormat(data->display, + PictStandardARGB32), + 0, NULL); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + XDamageDestroy(data->display, data->stencil_damage); + if (data->use_xdamage) { + data->stencil_damage = + XDamageCreate(data->display, data->stencil, XDamageReportNonEmpty); + XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts); + } +#endif + } +#endif if (renderer->info.flags & SDL_RENDERER_SINGLEBUFFER) { n = 0; } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) { @@ -301,25 +651,170 @@ if (data->pixmaps[i] != None) { XFreePixmap(data->display, data->pixmaps[i]); data->pixmaps[i] = None; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + XRenderFreePicture(data->display, data->pixmap_picts[i]); + data->pixmap_picts[i] = None; +#endif } } for (i = 0; i < n; ++i) { - data->pixmaps[i] = - XCreatePixmap(data->display, data->xwindow, window->w, window->h, - data->depth); +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + data->pixmaps[i] = + XCreatePixmap(data->display, + data->xwindow, + window->w, + window->h, + 32); + } + else +#endif + { + data->pixmaps[i] = + XCreatePixmap(data->display, data->xwindow, window->w, window->h, + data->depth); + } if (data->pixmaps[i] == None) { SDL_SetError("XCreatePixmap() failed"); return -1; } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + data->pixmap_picts[i] = + XRenderCreatePicture(data->display, + data->pixmaps[i], + XRenderFindStandardFormat(data->display, + PictStandardARGB32), + 0, None); + if (!data->pixmap_picts[i]) { + SDL_SetError("XRenderCreatePicture() failed"); + return -1; + } + XRenderComposite(data->display, + PictOpClear, + data->pixmap_picts[i], + None, + data->pixmap_picts[i], + 0, 0, + 0, 0, + 0, 0, + window->w, window->h); + + } +#endif } if (n > 0) { data->drawable = data->pixmaps[0]; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + data->drawable_pict = data->pixmap_picts[0]; +#endif } data->current_pixmap = 0; return 0; } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER +static void +SDLMaskToXRenderMask(Uint32 sdl_mask, short *comp, short *compMask) { + if (sdl_mask == 0) { + *comp = 0; + *compMask = 0; + } else { + (*comp) = 0; + (*compMask) = 0; + while(!(sdl_mask & 1)) { + (*comp)++; + sdl_mask >>= 1; + } + while(sdl_mask & 1) { + (*compMask) = ((*compMask) << 1) | 1; + sdl_mask >>= 1; + } + } +} + +static XRenderPictFormat* +PixelFormatEnumToXRenderPictFormat(SDL_Renderer * renderer, Uint32 format) { + XRenderPictFormat* pict_fmt = NULL; + X11_RenderData *data = (X11_RenderData *) renderer->driverdata; + + if (data->use_xrender) { + + int bpp; + Uint32 Amask, Rmask, Gmask, Bmask; + if(!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("Unknown pixel format"); + return NULL; + } + XRenderPictFormat templ; + unsigned long mask = (PictFormatType | PictFormatDepth | PictFormatRed | + PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | + PictFormatBlue | PictFormatBlueMask | PictFormatAlpha | + PictFormatAlphaMask); + + templ.type = PictTypeDirect; + templ.depth = bpp; + SDLMaskToXRenderMask(Amask, &(templ.direct.alpha), &(templ.direct.alphaMask)); + SDLMaskToXRenderMask(Rmask, &(templ.direct.red), &(templ.direct.redMask)); + SDLMaskToXRenderMask(Gmask, &(templ.direct.green), &(templ.direct.greenMask)); + SDLMaskToXRenderMask(Bmask, &(templ.direct.blue), &(templ.direct.blueMask)); + pict_fmt = XRenderFindFormat(data->display, mask, &templ, 0); + } + + return pict_fmt; +} + + +static Visual* +PixelFormatEnumToVisual(SDL_Renderer * renderer, Uint32 format) { + X11_RenderData *data = (X11_RenderData *) renderer->driverdata; + + if (data->use_xrender) { + int bpp; + Uint32 Amask, Rmask, Gmask, Bmask; + SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); + + XVisualInfo vinfo_templ; + long vinfo_mask; + int nitems_return; + + vinfo_mask = (VisualDepthMask | VisualRedMaskMask | + VisualGreenMaskMask | VisualBlueMaskMask); + vinfo_templ.depth = bpp; + vinfo_templ.red_mask = Rmask; + vinfo_templ.green_mask = Gmask; + vinfo_templ.blue_mask = Bmask; + + XVisualInfo * ret = XGetVisualInfo(data->display, vinfo_mask, + &vinfo_templ, &nitems_return); + + if (nitems_return) { + return ret[0].visual; + } + } + + return NULL; +} + +static XRenderColor +SDLColorToXRenderColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a) { + double rd, gd, bd, ad; + XRenderColor ret; + rd = r / 255.0; + gd = g / 255.0; + bd = b / 255.0; + ad = a / 255.0; + + ret.red = (unsigned short) (rd * ad * 0xFFFF); + ret.green = (unsigned short) (gd * ad * 0xFFFF); + ret.blue = (unsigned short) (bd * ad * 0xFFFF); + ret.alpha = (unsigned short) (ad * 0xFFFF); + + return ret; +} +#endif + static int X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { @@ -328,15 +823,18 @@ SDL_VideoDisplay *display = window->display; X11_TextureData *data; int pitch_alignmask = ((renderdata->scanline_pad / 8) - 1); - + XGCValues gcv; + data = (X11_TextureData *) SDL_calloc(1, sizeof(*data)); if (!data) { SDL_OutOfMemory(); return -1; } + data->depth = renderdata->depth; + data->visual = renderdata->visual; + data->gc = renderdata->gc; texture->driverdata = data; - if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { data->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h); @@ -345,18 +843,26 @@ } data->format = display->current_mode.format; } else { - /* The image/pixmap depth must be the same as the window or you - get a BadMatch error when trying to putimage or copyarea. - */ - if (texture->format != display->current_mode.format) { - SDL_SetError("Texture format doesn't match window format"); - return -1; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (renderdata->use_xrender) + { + Uint32 Amask, Rmask, Gmask, Bmask; + SDL_PixelFormatEnumToMasks(texture->format, &(data->depth), + &Rmask, &Gmask, &Bmask, &Amask); + data->visual = PixelFormatEnumToVisual(renderer, texture->format); + } + else +#endif + { + if (texture->format != display->current_mode.format) + { + SDL_SetError("Texture format doesn't match window format"); + return -1; + } } data->format = texture->format; } - data->pitch = texture->w * SDL_BYTESPERPIXEL(data->format); - data->pitch = (data->pitch + pitch_alignmask) & ~pitch_alignmask; - + if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) { #ifndef NO_SHARED_MEMORY XShmSegmentInfo *shminfo = &data->shminfo; @@ -364,37 +870,42 @@ shm_error = True; if (SDL_X11_HAVE_SHM) { - shminfo->shmid = - shmget(IPC_PRIVATE, texture->h * data->pitch, - IPC_CREAT | 0777); - if (shminfo->shmid >= 0) { - shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); - shminfo->readOnly = False; - if (shminfo->shmaddr != (char *) -1) { - shm_error = False; - X_handler = XSetErrorHandler(shm_errhandler); - XShmAttach(renderdata->display, shminfo); - XSync(renderdata->display, False); - XSetErrorHandler(X_handler); - if (shm_error) { - shmdt(shminfo->shmaddr); + data->image = + XShmCreateImage(renderdata->display, data->visual, + data->depth, ZPixmap, NULL, + shminfo, texture->w, texture->h); + if (data->image) { + shminfo->shmid = + shmget(IPC_PRIVATE, texture->h * data->image->bytes_per_line, + IPC_CREAT | 0777); + if (shminfo->shmid >= 0) { + shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); + shminfo->readOnly = False; + if (shminfo->shmaddr != (char *) -1) { + shm_error = False; + X_handler = XSetErrorHandler(shm_errhandler); + XShmAttach(renderdata->display, shminfo); + XSync(renderdata->display, False); + XSetErrorHandler(X_handler); + if (shm_error) { + XShmDetach(renderdata->display, shminfo); + shmdt(shminfo->shmaddr); + XDestroyImage(data->image); + XSync(renderdata->display, False); + } + else { + data->pixels = data->image->data = shminfo->shmaddr; + shmctl(shminfo->shmid, IPC_RMID, NULL); + data->pixmap = + XCreatePixmap(renderdata->display, renderdata->xwindow, + texture->w, texture->h, data->depth); + if (!data->pixmap) { + SDL_SetError("XCreatePixmap() failed"); + return -1; + } + } } } - shmctl(shminfo->shmid, IPC_RMID, NULL); - } - } - if (!shm_error) { - data->pixels = shminfo->shmaddr; - - data->image = - XShmCreateImage(renderdata->display, renderdata->visual, - renderdata->depth, ZPixmap, shminfo->shmaddr, - shminfo, texture->w, texture->h); - if (!data->image) { - XShmDetach(renderdata->display, shminfo); - XSync(renderdata->display, False); - shmdt(shminfo->shmaddr); - shm_error = True; } } if (shm_error) { @@ -403,47 +914,102 @@ if (!data->image) #endif /* not NO_SHARED_MEMORY */ { - data->pixels = SDL_malloc(texture->h * data->pitch); - if (!data->pixels) { - X11_DestroyTexture(renderer, texture); - SDL_OutOfMemory(); - return -1; - } - data->image = - XCreateImage(renderdata->display, renderdata->visual, - renderdata->depth, ZPixmap, 0, data->pixels, + XCreateImage(renderdata->display, data->visual, + data->depth, ZPixmap, 0, NULL, texture->w, texture->h, SDL_BYTESPERPIXEL(data->format) * 8, - data->pitch); + 0); if (!data->image) { X11_DestroyTexture(renderer, texture); SDL_SetError("XCreateImage() failed"); return -1; } + data->pixels = SDL_malloc(texture->h * data->image->bytes_per_line); + if (!data->pixels) { + X11_DestroyTexture(renderer, texture); + SDL_OutOfMemory(); + return -1; + } + data->image->data = data->pixels; + data->pixmap = + XCreatePixmap(renderdata->display, renderdata->xwindow, texture->w, + texture->h, data->depth); + if (data->pixmap == None) { + X11_DestroyTexture(renderer, texture); + SDL_SetError("XCreatePixmap() failed"); + return -1; + } } - } else { + } + else { + data->image = + XCreateImage(renderdata->display, data->visual, + data->depth, ZPixmap, 0, NULL, + texture->w, texture->h, + SDL_BYTESPERPIXEL(data->format) * 8, + 0); + if (!data->image) { + X11_DestroyTexture(renderer, texture); + SDL_SetError("XCreateImage() failed"); + return -1; + } data->pixmap = XCreatePixmap(renderdata->display, renderdata->xwindow, texture->w, - texture->h, renderdata->depth); + texture->h, data->depth); if (data->pixmap == None) { X11_DestroyTexture(renderer, texture); SDL_SetError("XCreatePixmap() failed"); return -1; } + } - data->image = - XCreateImage(renderdata->display, renderdata->visual, - renderdata->depth, ZPixmap, 0, NULL, texture->w, - texture->h, SDL_BYTESPERPIXEL(data->format) * 8, - data->pitch); - if (!data->image) { + data->pitch = data->image->bytes_per_line; + +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if(renderdata->use_xrender) { + gcv.graphics_exposures = False; + data->gc = + XCreateGC(renderdata->display, data->pixmap, GCGraphicsExposures, &gcv); + if (!data->gc) { + SDL_SetError("XCreateGC() failed"); + return -1; + } + data->picture_fmt = + PixelFormatEnumToXRenderPictFormat(renderer, texture->format); + if (data->picture_fmt == NULL) { X11_DestroyTexture(renderer, texture); - SDL_SetError("XCreateImage() failed"); + SDL_SetError("Texture format not supported by driver"); return -1; } + data->picture = + XRenderCreatePicture(renderdata->display, data->pixmap, + data->picture_fmt, 0, NULL); + if (!data->picture) { + X11_DestroyTexture(renderer, texture); + SDL_SetError("XRenderCreatePicture() failed"); + return -1; + } + data->modulated_pixmap = + XCreatePixmap(renderdata->display, renderdata->xwindow, + texture->w, texture->h, data->depth); + if (!data->modulated_pixmap) { + X11_DestroyTexture(renderer, texture); + SDL_SetError("XCreatePixmap() failed"); + return -1; + } + data->modulated_picture = + XRenderCreatePicture(renderdata->display, data->modulated_pixmap, + data->picture_fmt, 0, NULL); + if (!data->modulated_picture) { + X11_DestroyTexture(renderer, texture); + SDL_SetError("XRenderCreatePicture() failed"); + return -1; + } + texture->blendMode = SDL_BLENDMODE_NONE; + data->blend_op = PictOpSrc; } - +#endif return 0; } @@ -463,14 +1029,106 @@ } static int +X11_SetTextureRGBAMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + + X11_TextureData *data = (X11_TextureData *) texture->driverdata; + X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata; + + if (renderdata->use_xrender) { + + Uint8 r = 0xFF, g = 0xFF, b = 0xFF, a = 0xFF; + + /* Check if alpha modulation is required. */ + if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) { + a = texture->a; + } + + /* Check if color modulation is required. */ + if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) { + r = texture->r; + g = texture->g; + b = texture->b; + } + + /* We can save some labour if no modulation is required. */ + if (texture->modMode != SDL_TEXTUREMODULATE_NONE) { + XRenderColor mod_color = + SDLColorToXRenderColor(r, g, b, a); + XRenderFillRectangle(renderdata->display, PictOpSrc, + renderdata->brush_pict, &mod_color, + 0, 0, 1, 1); + } + + /* We can save some labour dealing with component alpha + * if color modulation is not required. */ + XRenderPictureAttributes attr; + if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) { + attr.component_alpha = True; + XRenderChangePicture(renderdata->display, renderdata->brush_pict, + CPComponentAlpha, &attr); + } + + /* Again none of this is necessary is no modulation + * is required. */ + if (texture->modMode != SDL_TEXTUREMODULATE_NONE) { + XRenderComposite(renderdata->display, PictOpSrc, + data->picture, renderdata->brush_pict, + data->modulated_picture, + 0, 0, 0, 0, 0, 0, texture->w, texture->h); + } + + /* We only need to reset the component alpha + * attribute if color modulation is required. */ + if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) { + attr.component_alpha = False; + XRenderChangePicture(renderdata->display, renderdata->brush_pict, + CPComponentAlpha, &attr); + } + + return 0; + } + else { + SDL_Unsupported(); + return -1; + } +} + +static int X11_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) { + X11_TextureData *data = (X11_TextureData *) texture->driverdata; + X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata; switch (texture->blendMode) { case SDL_BLENDMODE_NONE: +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (renderdata->use_xrender) { + data->blend_op = PictOpSrc; + return 0; + } + case SDL_BLENDMODE_MOD: + case SDL_BLENDMODE_MASK: + case SDL_BLENDMODE_BLEND: + if (renderdata->use_xrender) { + data->blend_op = PictOpOver; + return 0; + } + case SDL_BLENDMODE_ADD: + if (renderdata->use_xrender) { + data->blend_op = PictOpAdd; + return 0; + } +#endif return 0; default: SDL_Unsupported(); texture->blendMode = SDL_BLENDMODE_NONE; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (renderdata->use_xrender) { + texture->blendMode = SDL_BLENDMODE_BLEND; + data->blend_op = PictOpOver; + } +#endif return -1; } } @@ -479,6 +1137,7 @@ X11_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) { X11_TextureData *data = (X11_TextureData *) texture->driverdata; + X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata; switch (texture->scaleMode) { case SDL_TEXTURESCALEMODE_NONE: @@ -488,10 +1147,33 @@ if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) { return 0; } - /* Fall through to unsupported case */ +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (renderdata->use_xrender) { + data->filter = FilterFast; + return 0; + } + case SDL_TEXTURESCALEMODE_SLOW: + if (renderdata->use_xrender) { + data->filter = FilterGood; + return 0; + } + case SDL_TEXTURESCALEMODE_BEST: + if (renderdata->use_xrender) { + data->filter = FilterBest; + return 0; + } +#endif + /* Fall through to unsupported case */ default: SDL_Unsupported(); - texture->scaleMode = SDL_TEXTURESCALEMODE_NONE; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (renderdata->use_xrender) { + texture->scaleMode = SDL_TEXTURESCALEMODE_FAST; + data->filter = FilterFast; + } + else +#endif + texture->scaleMode = SDL_TEXTURESCALEMODE_NONE; return -1; } return 0; @@ -532,7 +1214,7 @@ data->image->height = rect->h; data->image->data = (char *) pixels; data->image->bytes_per_line = pitch; - XPutImage(renderdata->display, data->pixmap, renderdata->gc, + XPutImage(renderdata->display, data->pixmap, data->gc, data->image, 0, 0, rect->x, rect->y, rect->w, rect->h); } return 0; @@ -575,12 +1257,36 @@ static int X11_SetDrawBlendMode(SDL_Renderer * renderer) { + X11_RenderData *data = (X11_RenderData *) renderer->driverdata; switch (renderer->blendMode) { case SDL_BLENDMODE_NONE: +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + //PictOpSrc + data->blend_op = PictOpSrc; + return 0; + case SDL_BLENDMODE_MOD: + case SDL_BLENDMODE_MASK: + case SDL_BLENDMODE_BLEND: // PictOpOver + data->blend_op = PictOpOver; + return 0; + case SDL_BLENDMODE_ADD: // PictOpAdd + data->blend_op = PictOpAdd; + return 0; + /* FIXME case SDL_BLENDMODE_MOD: */ +#endif return 0; default: SDL_Unsupported(); - renderer->blendMode = SDL_BLENDMODE_NONE; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if(data->use_xrender) { + renderer->blendMode = SDL_BLENDMODE_BLEND; + data->blend_op = PictOpOver; + } + else +#endif + { + renderer->blendMode = SDL_BLENDMODE_NONE; + } return -1; } } @@ -601,16 +1307,35 @@ return SDL_MapRGBA(&data->format, r, g, b, a); } +static XRenderColor +xrenderdrawcolor(SDL_Renderer *renderer) +{ + XRenderColor xrender_color; + if(renderer->blendMode == SDL_BLENDMODE_NONE) { + xrender_color = + SDLColorToXRenderColor(renderer->r, renderer->g, renderer->b, 0xFF); + } + else { + xrender_color = + SDLColorToXRenderColor(renderer->r, renderer->g, renderer->b, renderer->a); + } + return xrender_color; +} + static int X11_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, int count) { X11_RenderData *data = (X11_RenderData *) renderer->driverdata; SDL_Window *window = renderer->window; - unsigned long foreground; XPoint *xpoints, *xpoint; int i, xcount; + SDL_Rect clip; + clip.x = 0; + clip.y = 0; + clip.w = window->w; + clip.h = window->h; if (data->makedirty) { SDL_Rect rect; @@ -625,27 +1350,105 @@ } SDL_AddDirtyRect(&data->dirty, &rect); } + { + xpoint = xpoints = SDL_stack_alloc(XPoint, count); + xcount = 0; + for (i = 0; i < count; ++i) { + int x = points[i].x; + int y = points[i].y; + if (x < 0 || x >= window->w || y < 0 || y >= window->h) { + continue; + } + xpoint->x = (short)x; + xpoint->y = (short)y; + ++xpoint; + ++xcount; + } - foreground = renderdrawcolor(renderer, 1); - XSetForeground(data->display, data->gc, foreground); +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && + (renderer->blendMode != SDL_BLENDMODE_NONE) && + !(renderer->a == 0xFF && + renderer->blendMode != SDL_BLENDMODE_ADD && + renderer->blendMode != SDL_BLENDMODE_MOD)) + { + XSetForeground(data->display, data->stencil_gc, 0); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + { + /* Update only those parts which were changed + * in the previous drawing operation */ + XFixesSetGCClipRegion(data->display, data->stencil_gc, + 0, 0, data->stencil_parts); + } +#endif + XFillRectangle(data->display, data->stencil, data->stencil_gc, + 0, 0, window->w, window->h); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + { + XFixesSetGCClipRegion(data->display, data->stencil_gc, 0, 0, None); + } +#endif + XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF); - xpoint = xpoints = SDL_stack_alloc(XPoint, count); - xcount = 0; - for (i = 0; i < count; ++i) { - int x = points[i].x; - int y = points[i].y; - if (x < 0 || x >= window->w || y < 0 || y >= window->h) { - continue; + XDrawPoints(data->display, data->stencil, data->stencil_gc, xpoints, xcount, + CoordModeOrigin); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + { + /* Store the damaged region in stencil_parts */ + XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts); + } +#endif } - xpoint->x = (short)x; - xpoint->y = (short)y; - ++xpoint; - ++xcount; +#endif } - if (xcount > 0) { - XDrawPoints(data->display, data->drawable, data->gc, xpoints, xcount, - CoordModeOrigin); + +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && + (renderer->blendMode != SDL_BLENDMODE_NONE) && + !(renderer->a == 0xFF && + renderer->blendMode != SDL_BLENDMODE_ADD && + renderer->blendMode != SDL_BLENDMODE_MOD)) + { + XRenderColor foreground; + foreground = xrenderdrawcolor(renderer); + + XRenderFillRectangle(data->display, PictOpSrc, data->brush_pict, + &foreground, 0, 0, 1, 1); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + { + /* Update only those parts which drawn + * to in the current drawing operation */ + XFixesSetPictureClipRegion(data->display, data->drawable_pict, + 0, 0, data->stencil_parts); + } +#endif + XRenderComposite(data->display, data->blend_op, data->brush_pict, + data->stencil_pict, data->drawable_pict, + 0, 0, 0, 0, 0, 0, window->w, window->h); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + { + XFixesSetPictureClipRegion(data->display, data->drawable_pict, 0, 0, None); + } +#endif } + else +#endif + { + unsigned long foreground = renderdrawcolor(renderer, 1); + XSetForeground(data->display, data->gc, foreground); + + + if (xcount > 0) { + XDrawPoints(data->display, data->drawable, data->gc, xpoints, xcount, + CoordModeOrigin); + } + } + SDL_stack_free(xpoints); return 0; @@ -668,65 +1471,146 @@ clip.y = 0; clip.w = window->w; clip.h = window->h; - - foreground = renderdrawcolor(renderer, 1); - XSetForeground(data->display, data->gc, foreground); - - xpoint = xpoints = SDL_stack_alloc(XPoint, count); - xcount = 0; - minx = INT_MAX; - miny = INT_MAX; - maxx = INT_MIN; - maxy = INT_MIN; - for (i = 0; i < count; ++i) { - int x = points[i].x; - int y = points[i].y; + { + Pixmap drawable; + GC gc; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && + (renderer->blendMode != SDL_BLENDMODE_NONE) && + !(renderer->a == 0xFF && + renderer->blendMode != SDL_BLENDMODE_ADD && + renderer->blendMode != SDL_BLENDMODE_MOD)) + { + drawable = data->stencil; + gc = data->stencil_gc; - /* If the point is inside the window, add it to the list */ - if (x >= 0 && x < window->w && y >= 0 && y < window->h) { - if (x < minx) { - minx = x; - } else if (x > maxx) { - maxx = x; - } - if (y < miny) { - miny = y; - } else if (y > maxy) { - maxy = y; - } - xpoint->x = (short)x; - xpoint->y = (short)y; - ++xpoint; - ++xcount; - continue; + XSetForeground(data->display, data->stencil_gc, 0); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetGCClipRegion(data->display, data->stencil_gc, + 0, 0, data->stencil_parts); +#endif + XFillRectangle(data->display, data->stencil, data->stencil_gc, + 0, 0, window->w, window->h); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetGCClipRegion(data->display, data->stencil_gc, + 0, 0, None); +#endif + XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF); + } + else +#endif + { + drawable = data->drawable; + gc = data->gc; } - /* We need to clip the line segments joined by this point */ - if (xcount > 0) { - int x1 = xpoint[-1].x; - int y1 = xpoint[-1].y; - int x2 = x; - int y2 = y; - if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) { - if (x2 < minx) { - minx = x2; - } else if (x2 > maxx) { - maxx = x2; + foreground = renderdrawcolor(renderer, 1); + XSetForeground(data->display, data->gc, foreground); + + xpoint = xpoints = SDL_stack_alloc(XPoint, count); + xcount = 0; + minx = INT_MAX; + miny = INT_MAX; + maxx = INT_MIN; + maxy = INT_MIN; + for (i = 0; i < count; ++i) { + int x = points[i].x; + int y = points[i].y; + + /* If the point is inside the window, add it to the list */ + if (x >= 0 && x < window->w && y >= 0 && y < window->h) { + if (x < minx) { + minx = x; + } else if (x > maxx) { + maxx = x; } - if (y2 < miny) { - miny = y2; - } else if (y2 > maxy) { - maxy = y2; + if (y < miny) { + miny = y; + } else if (y > maxy) { + maxy = y; } - xpoint->x = (short)x2; - xpoint->y = (short)y2; + xpoint->x = (short)x; + xpoint->y = (short)y; ++xpoint; ++xcount; + continue; } - XDrawLines(data->display, data->drawable, data->gc, - xpoints, xcount, CoordModeOrigin); + + /* We need to clip the line segments joined by this point */ + if (xcount > 0) { + int x1 = xpoint[-1].x; + int y1 = xpoint[-1].y; + int x2 = x; + int y2 = y; + if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) { + if (x2 < minx) { + minx = x2; + } else if (x2 > maxx) { + maxx = x2; + } + if (y2 < miny) { + miny = y2; + } else if (y2 > maxy) { + maxy = y2; + } + xpoint->x = (short)x2; + xpoint->y = (short)y2; + ++xpoint; + ++xcount; + } + XDrawLines(data->display, drawable, gc, + xpoints, xcount, CoordModeOrigin); + if (xpoints[0].x != x2 || xpoints[0].y != y2) { + XDrawPoint(data->display, drawable, gc, x2, y2); + } + if (data->makedirty) { + SDL_Rect rect; + + rect.x = minx; + rect.y = miny; + rect.w = (maxx - minx) + 1; + rect.h = (maxy - miny) + 1; + SDL_AddDirtyRect(&data->dirty, &rect); + } + xpoint = xpoints; + xcount = 0; + minx = INT_MAX; + miny = INT_MAX; + maxx = INT_MIN; + maxy = INT_MIN; + } + if (i < (count-1)) { + int x1 = x; + int y1 = y; + int x2 = points[i+1].x; + int y2 = points[i+1].y; + if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) { + if (x1 < minx) { + minx = x1; + } else if (x1 > maxx) { + maxx = x1; + } + if (y1 < miny) { + miny = y1; + } else if (y1 > maxy) { + maxy = y1; + } + xpoint->x = (short)x1; + xpoint->y = (short)y1; + ++xpoint; + ++xcount; + } + } + } + if (xcount > 1) { + int x2 = xpoint[-1].x; + int y2 = xpoint[-1].y; + XDrawLines(data->display, drawable, gc, xpoints, xcount, + CoordModeOrigin); if (xpoints[0].x != x2 || xpoints[0].y != y2) { - XDrawPoint(data->display, data->drawable, data->gc, x2, y2); + XDrawPoint(data->display, drawable, gc, x2, y2); } if (data->makedirty) { SDL_Rect rect; @@ -737,54 +1621,37 @@ rect.h = (maxy - miny) + 1; SDL_AddDirtyRect(&data->dirty, &rect); } - xpoint = xpoints; - xcount = 0; - minx = INT_MAX; - miny = INT_MAX; - maxx = INT_MIN; - maxy = INT_MIN; - } - if (i < (count-1)) { - int x1 = x; - int y1 = y; - int x2 = points[i+1].x; - int y2 = points[i+1].y; - if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) { - if (x1 < minx) { - minx = x1; - } else if (x1 > maxx) { - maxx = x1; - } - if (y1 < miny) { - miny = y1; - } else if (y1 > maxy) { - maxy = y1; - } - xpoint->x = (short)x1; - xpoint->y = (short)y1; - ++xpoint; - ++xcount; - } } } - if (xcount > 1) { - int x2 = xpoint[-1].x; - int y2 = xpoint[-1].y; - XDrawLines(data->display, data->drawable, data->gc, xpoints, xcount, - CoordModeOrigin); - if (xpoints[0].x != x2 || xpoints[0].y != y2) { - XDrawPoint(data->display, data->drawable, data->gc, x2, y2); +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && + (renderer->blendMode != SDL_BLENDMODE_NONE) && + !(renderer->a == 0xFF && + renderer->blendMode != SDL_BLENDMODE_ADD && + renderer->blendMode != SDL_BLENDMODE_MOD)) + { + XRenderColor xrforeground = xrenderdrawcolor(renderer); + XRenderFillRectangle(data->display, PictOpSrc, data->brush_pict, + &xrforeground, 0, 0, 1, 1); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + { + XDamageSubtract(data->display, data->stencil_damage, None, data->stencil_parts); + + XFixesSetPictureClipRegion(data->display, data->drawable_pict, + 0, 0, data->stencil_parts); } - if (data->makedirty) { - SDL_Rect rect; - - rect.x = minx; - rect.y = miny; - rect.w = (maxx - minx) + 1; - rect.h = (maxy - miny) + 1; - SDL_AddDirtyRect(&data->dirty, &rect); - } +#endif + XRenderComposite(data->display, data->blend_op, data->brush_pict, + data->stencil_pict, data->drawable_pict, + 0, 0, 0, 0, 0, 0, window->w, window->h); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetPictureClipRegion(data->display, data->drawable_pict, + 0, 0, None); +#endif } +#endif SDL_stack_free(xpoints); return 0; @@ -796,18 +1663,122 @@ X11_RenderData *data = (X11_RenderData *) renderer->driverdata; SDL_Window *window = renderer->window; SDL_Rect clip, rect; - unsigned long foreground; + int i, xcount; XRectangle *xrects, *xrect; - int i, xcount; - + xrect = xrects = SDL_stack_alloc(XRectangle, count); + xcount = 0; + clip.x = 0; clip.y = 0; clip.w = window->w; clip.h = window->h; + { - foreground = renderdrawcolor(renderer, 1); - XSetForeground(data->display, data->gc, foreground); + for (i = 0; i < count; ++i) { + if (!SDL_IntersectRect(rects[i], &clip, &rect)) { + continue; + } + + xrect->x = (short)rect.x; + xrect->y = (short)rect.y; + xrect->width = (unsigned short)rect.w - 1; + xrect->height = (unsigned short)rect.h - 1; + ++xrect; + ++xcount; + + if (data->makedirty) { + SDL_AddDirtyRect(&data->dirty, &rect); + } + } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && + (renderer->blendMode != SDL_BLENDMODE_NONE) && + !(renderer->a == 0xFF && + renderer->blendMode != SDL_BLENDMODE_ADD && + renderer->blendMode != SDL_BLENDMODE_MOD)) + { + XSetForeground(data->display, data->stencil_gc, 0); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetGCClipRegion(data->display, data->stencil_gc, + 0, 0, data->stencil_parts); +#endif + XFillRectangle(data->display, data->stencil, data->stencil_gc, + 0, 0, window->w, window->h); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetGCClipRegion(data->display, data->stencil_gc, + 0, 0, None); +#endif + XSetForeground(data->display, data->stencil_gc, 0xFFFFFFFF); + + XDrawRectangles(data->display, data->stencil, data->stencil_gc, xrects, xcount); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XDamageSubtract(data->display, data->stencil_damage, + None, data->stencil_parts); +#endif + } +#endif + } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && + (renderer->blendMode != SDL_BLENDMODE_NONE) && + !(renderer->a == 0xFF && + renderer->blendMode != SDL_BLENDMODE_ADD && + renderer->blendMode != SDL_BLENDMODE_MOD)) + { + XRenderColor foreground; + foreground = xrenderdrawcolor(renderer); + XRenderFillRectangle(data->display, PictOpSrc, data->brush_pict, + &foreground, 0, 0, 1, 1); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetPictureClipRegion(data->display, data->drawable_pict, + 0, 0, data->stencil_parts); +#endif + XRenderComposite(data->display, data->blend_op, data->brush_pict, + data->stencil_pict, data->drawable_pict, + 0, 0, 0, 0, 0, 0, window->w, window->h); +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage) + XFixesSetPictureClipRegion(data->display, data->drawable_pict, + 0, 0, None); +#endif + } + else +#endif + { + unsigned long foreground; + + foreground = renderdrawcolor(renderer, 1); + XSetForeground(data->display, data->gc, foreground); + + if (xcount > 0) { + XDrawRectangles(data->display, data->drawable, data->gc, + xrects, xcount); + } + } + SDL_stack_free(xrects); + + return 0; +} + +static int +X11_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) +{ + X11_RenderData *data = (X11_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + SDL_Rect clip, rect; + + clip.x = 0; + clip.y = 0; + clip.w = window->w; + clip.h = window->h; + + int i, xcount; + XRectangle *xrects, *xrect; xrect = xrects = SDL_stack_alloc(XRectangle, count); xcount = 0; for (i = 0; i < count; ++i) { @@ -826,57 +1797,34 @@ SDL_AddDirtyRect(&data->dirty, &rect); } } - if (xcount > 0) { - XDrawRectangles(data->display, data->drawable, data->gc, - xrects, xcount); - } - SDL_stack_free(xpoints); - return 0; -} - -static int -X11_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) -{ - X11_RenderData *data = (X11_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - SDL_Rect clip, rect; - unsigned long foreground; - XRectangle *xrects, *xrect; - int i, xcount; - - clip.x = 0; - clip.y = 0; - clip.w = window->w; - clip.h = window->h; - - foreground = renderdrawcolor(renderer, 1); - XSetForeground(data->display, data->gc, foreground); - - xrect = xrects = SDL_stack_alloc(XRectangle, count); - xcount = 0; - for (i = 0; i < count; ++i) { - if (!SDL_IntersectRect(rects[i], &clip, &rect)) { - continue; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + XRenderColor foreground; + foreground = xrenderdrawcolor(renderer); + if (xcount == 1) { + XRenderFillRectangle(data->display, data->blend_op, data->drawable_pict, + &foreground, xrects[0].x, xrects[0].y, + xrects[0].width, xrects[0].height); } - - xrect->x = (short)rect.x; - xrect->y = (short)rect.y; - xrect->width = (unsigned short)rect.w; - xrect->height = (unsigned short)rect.h; - ++xrect; - ++xcount; - - if (data->makedirty) { - SDL_AddDirtyRect(&data->dirty, &rect); + else if (xcount > 1) { + XRenderFillRectangles(data->display, data->blend_op, data->drawable_pict, + &foreground, xrects, xcount); } } - if (xcount > 0) { + else +#endif + { + unsigned long foreground; + + foreground = renderdrawcolor(renderer, 1); + XSetForeground(data->display, data->gc, foreground); + XFillRectangles(data->display, data->drawable, data->gc, xrects, xcount); } - SDL_stack_free(xpoints); + SDL_stack_free(xrects); return 0; } @@ -890,103 +1838,206 @@ if (data->makedirty) { SDL_AddDirtyRect(&data->dirty, dstrect); } - if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) { +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + if(texture->access == SDL_TEXTUREACCESS_STREAMING) { #ifndef NO_SHARED_MEMORY - if (texturedata->shminfo.shmaddr) { - XShmPutImage(data->display, data->drawable, data->gc, - texturedata->image, srcrect->x, srcrect->y, - dstrect->x, dstrect->y, srcrect->w, srcrect->h, - False); - } else + if(texturedata->shminfo.shmaddr) { + XShmPutImage(data->display, texturedata->pixmap, texturedata->gc, + texturedata->image, srcrect->x, srcrect->y, + srcrect->x, srcrect->y, srcrect->w, srcrect->h, + False); + } + else #endif - if (texturedata->pixels) { - XPutImage(data->display, data->drawable, data->gc, - texturedata->image, srcrect->x, srcrect->y, dstrect->x, - dstrect->y, srcrect->w, srcrect->h); + if (texturedata->pixels) { + XPutImage(data->display, texturedata->pixmap, texturedata->gc, + texturedata->image, srcrect->x, srcrect->y, srcrect->x, + srcrect->y, srcrect->w, srcrect->h); + } + XSync(data->display, False); + } + Picture src, mask; + XRenderPictureAttributes attr; + const SDL_Rect *mrect; + + if (texture->modMode == SDL_TEXTUREMODULATE_NONE) { + src = texturedata->picture; + } + else { + src = texturedata->modulated_picture; + } + + if(texture->blendMode == SDL_BLENDMODE_NONE) + { + mask = None; + mrect = srcrect; + } + else if (texture->blendMode == SDL_BLENDMODE_MOD) + { + mask = data->stencil_pict; + mrect = dstrect; + } + else + { + mask = texturedata->picture; + mrect = srcrect; + } + + if(srcrect->w == dstrect->w && srcrect->h == dstrect->h) { + if (texture->blendMode == SDL_BLENDMODE_MOD) { + XRenderComposite(data->display, PictOpSrc, data->drawable_pict, + src, data->stencil_pict, + dstrect->x, dstrect->y, srcrect->x, srcrect->y, + dstrect->x, dstrect->y, dstrect->w, dstrect->h); + attr.component_alpha = True; + XRenderChangePicture(data->display, data->stencil_pict, + CPComponentAlpha, &attr); + } + XRenderComposite(data->display, texturedata->blend_op, + src, mask, data->drawable_pict, srcrect->x, srcrect->y, + mrect->x, mrect->y, dstrect->x, dstrect->y, + dstrect->w, dstrect->h); } else { - XCopyArea(data->display, texturedata->pixmap, data->drawable, - data->gc, srcrect->x, srcrect->y, dstrect->w, - dstrect->h, dstrect->x, dstrect->y); - } - } else if (texturedata->yuv - || texture->access == SDL_TEXTUREACCESS_STREAMING) { - SDL_Surface src, dst; - SDL_PixelFormat fmt; - SDL_Rect rect; - XImage *image = texturedata->scaling_image; - - if (!image) { - void *pixels; - int pitch; - - pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format); - pixels = SDL_malloc(dstrect->h * pitch); - if (!pixels) { - SDL_OutOfMemory(); - return -1; + double xscale = ((double) dstrect->w) / srcrect->w; + double yscale = ((double) dstrect->h) / srcrect->h; + XTransform xform = {{ + {XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0)}, + {XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0)}, + {XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(xscale * yscale)}}}; + XRenderSetPictureTransform(data->display, src, &xform); + + if (texture->blendMode == SDL_BLENDMODE_MOD) { + XRenderComposite(data->display, PictOpSrc, data->drawable_pict, + src, data->stencil_pict, + dstrect->x, dstrect->y, srcrect->x, srcrect->y, + dstrect->x, dstrect->y, dstrect->w, dstrect->h); + attr.component_alpha = True; + XRenderChangePicture(data->display, data->stencil_pict, + CPComponentAlpha, &attr); } - image = - XCreateImage(data->display, data->visual, data->depth, - ZPixmap, 0, pixels, dstrect->w, dstrect->h, - SDL_BYTESPERPIXEL(texturedata->format) * 8, - pitch); + XRenderSetPictureFilter(data->display, src, + texturedata->filter, 0, 0); + + XRenderComposite(data->display, texturedata->blend_op, + src, mask, data->drawable_pict, + srcrect->x, srcrect->y, mrect->x, mrect->y, + dstrect->x, dstrect->y, dstrect->w, dstrect->h); + + XTransform identity = {{ + {XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0)}, + {XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0)}, + {XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1)}}}; + XRenderSetPictureTransform(data->display, src, &identity); + } + if (renderer->blendMode == SDL_BLENDMODE_MOD) { + attr.component_alpha = False; + XRenderChangePicture(data->display, data->stencil_pict, + CPComponentAlpha, &attr); + } + } + else +#endif + { + if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) { +#ifndef NO_SHARED_MEMORY + if (texturedata->shminfo.shmaddr) { + XShmPutImage(data->display, data->drawable, data->gc, + texturedata->image, srcrect->x, srcrect->y, + dstrect->x, dstrect->y, srcrect->w, srcrect->h, + False); + } else +#endif + if (texturedata->pixels) { + XPutImage(data->display, data->drawable, data->gc, + texturedata->image, srcrect->x, srcrect->y, dstrect->x, + dstrect->y, srcrect->w, srcrect->h); + } else { + XCopyArea(data->display, texturedata->pixmap, data->drawable, + data->gc, srcrect->x, srcrect->y, dstrect->w, + dstrect->h, dstrect->x, dstrect->y); + } + } else if (texturedata->yuv + || texture->access == SDL_TEXTUREACCESS_STREAMING) { + SDL_Surface src, dst; + SDL_PixelFormat fmt; + SDL_Rect rect; + XImage *image = texturedata->scaling_image; + if (!image) { - SDL_SetError("XCreateImage() failed"); + void *pixels; + int pitch; + + pitch = dstrect->w * SDL_BYTESPERPIXEL(texturedata->format); + pixels = SDL_malloc(dstrect->h * pitch); + if (!pixels) { + SDL_OutOfMemory(); + return -1; + } + + image = + XCreateImage(data->display, data->visual, data->depth, + ZPixmap, 0, pixels, dstrect->w, dstrect->h, + SDL_BYTESPERPIXEL(texturedata->format) * 8, + pitch); + if (!image) { + SDL_SetError("XCreateImage() failed"); + return -1; + } + texturedata->scaling_image = image; + + } else if (image->width != dstrect->w || image->height != dstrect->h + || !image->data) { + image->width = dstrect->w; + image->height = dstrect->h; + image->bytes_per_line = + image->width * SDL_BYTESPERPIXEL(texturedata->format); + image->data = + (char *) SDL_realloc(image->data, + image->height * image->bytes_per_line); + if (!image->data) { + SDL_OutOfMemory(); + return -1; + } + } + + /* Set up fake surfaces for SDL_SoftStretch() */ + SDL_zero(src); + src.format = &fmt; + src.w = texture->w; + src.h = texture->h; +#ifndef NO_SHARED_MEMORY + if (texturedata->shminfo.shmaddr) { + src.pixels = texturedata->shminfo.shmaddr; + } else +#endif + src.pixels = texturedata->pixels; + src.pitch = texturedata->pitch; + + SDL_zero(dst); + dst.format = &fmt; + dst.w = image->width; + dst.h = image->height; + dst.pixels = image->data; + dst.pitch = image->bytes_per_line; + + fmt.BytesPerPixel = SDL_BYTESPERPIXEL(texturedata->format); + + rect.x = 0; + rect.y = 0; + rect.w = dstrect->w; + rect.h = dstrect->h; + if (SDL_SoftStretch(&src, srcrect, &dst, &rect) < 0) { return -1; } - texturedata->scaling_image = image; - - } else if (image->width != dstrect->w || image->height != dstrect->h - || !image->data) { - image->width = dstrect->w; - image->height = dstrect->h; - image->bytes_per_line = - image->width * SDL_BYTESPERPIXEL(texturedata->format); - image->data = - (char *) SDL_realloc(image->data, - image->height * image->bytes_per_line); - if (!image->data) { - SDL_OutOfMemory(); - return -1; - } + XPutImage(data->display, data->drawable, data->gc, image, 0, 0, + dstrect->x, dstrect->y, dstrect->w, dstrect->h); + } else { + XCopyArea(data->display, texturedata->pixmap, data->drawable, + data->gc, srcrect->x, srcrect->y, dstrect->w, dstrect->h, + srcrect->x, srcrect->y); } - - /* Set up fake surfaces for SDL_SoftStretch() */ - SDL_zero(src); - src.format = &fmt; - src.w = texture->w; - src.h = texture->h; -#ifndef NO_SHARED_MEMORY - if (texturedata->shminfo.shmaddr) { - src.pixels = texturedata->shminfo.shmaddr; - } else -#endif - src.pixels = texturedata->pixels; - src.pitch = texturedata->pitch; - - SDL_zero(dst); - dst.format = &fmt; - dst.w = image->width; - dst.h = image->height; - dst.pixels = image->data; - dst.pitch = image->bytes_per_line; - - fmt.BytesPerPixel = SDL_BYTESPERPIXEL(texturedata->format); - - rect.x = 0; - rect.y = 0; - rect.w = dstrect->w; - rect.h = dstrect->h; - if (SDL_SoftStretch(&src, srcrect, &dst, &rect) < 0) { - return -1; - } - XPutImage(data->display, data->drawable, data->gc, image, 0, 0, - dstrect->x, dstrect->y, dstrect->w, dstrect->h); - } else { - XCopyArea(data->display, texturedata->pixmap, data->drawable, - data->gc, srcrect->x, srcrect->y, dstrect->w, dstrect->h, - srcrect->x, srcrect->y); } return 0; } @@ -1065,9 +2116,26 @@ if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) { for (dirty = data->dirty.list; dirty; dirty = dirty->next) { const SDL_Rect *rect = &dirty->rect; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) + { + XRenderComposite(data->display, + data->blend_op, + data->drawable_pict, + None, + data->xwindow_pict, + rect->x, rect->y, + 0, 0, + rect->x, rect->y, + rect->w, rect->h); + } + else +#endif + { XCopyArea(data->display, data->drawable, data->xwindow, data->gc, rect->x, rect->y, rect->w, rect->h, rect->x, rect->y); + } } SDL_ClearDirtyRects(&data->dirty); } @@ -1077,9 +2145,15 @@ if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) { data->current_pixmap = (data->current_pixmap + 1) % 2; data->drawable = data->pixmaps[data->current_pixmap]; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + data->drawable_pict = data->pixmap_picts[data->current_pixmap]; +#endif } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) { data->current_pixmap = (data->current_pixmap + 1) % 3; data->drawable = data->pixmaps[data->current_pixmap]; +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + data->drawable_pict = data->pixmap_picts[data->current_pixmap]; +#endif } } @@ -1110,6 +2184,19 @@ data->pixels = NULL; } #endif +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (renderdata->use_xrender) { + if (data->picture) { + XRenderFreePicture(renderdata->display, data->picture); + } + if (data->modulated_pixmap) { + XFreePixmap(renderdata->display, data->modulated_pixmap); + } + if (data->modulated_picture) { + XRenderFreePicture(renderdata->display, data->modulated_picture); + } + } +#endif if (data->scaling_image) { SDL_free(data->scaling_image->data); data->scaling_image->data = NULL; @@ -1133,10 +2220,36 @@ if (data->pixmaps[i] != None) { XFreePixmap(data->display, data->pixmaps[i]); } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender && data->pixmap_picts[i]) { + XRenderFreePicture(data->display, data->pixmap_picts[i]); + } +#endif } if (data->gc) { XFreeGC(data->display, data->gc); } +#ifdef SDL_VIDEO_DRIVER_X11_XRENDER + if (data->use_xrender) { + if (data->stencil_gc) { + XFreeGC(data->display, data->stencil_gc); + } + if (data->stencil) { + XFreePixmap(data->display, data->stencil); + } + if (data->stencil_pict) { + XRenderFreePicture(data->display, data->stencil_pict); + } + if (data->xwindow_pict) { + XRenderFreePicture(data->display, data->xwindow_pict); + } +#ifdef SDL_VIDEO_DRIVER_X11_XDAMAGE + if (data->use_xdamage && data->stencil_damage) { + XDamageDestroy(data->display, data->stencil_damage); + } +#endif + } +#endif SDL_FreeDirtyRects(&data->dirty); SDL_free(data); }