From 9fd29492c1b47fb0618997e9937ca7da57975d9a Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 6 Aug 2009 08:12:22 +0200 Subject: [PATCH] winex11.drv: Add support for XShm pixmaps. Most of this is "Copyright 2004 Huw Davies for CodeWeavers", I just did a little bit of integration. --- dlls/winex11.drv/dib.c | 286 ++++++++++++++++++++++++-------------- dlls/winex11.drv/x11drv.h | 8 ++ 2 files changed, 193 insertions(+), 101 deletions(-) diff --git a/dlls/winex11.drv/dib.c b/dlls/winex11.drv/dib.c index 07ce9e1ebec..effe1a480bd 100644 --- a/dlls/winex11.drv/dib.c +++ b/dlls/winex11.drv/dib.c @@ -62,31 +62,32 @@ static int ximageDepthTable[32]; /* This structure holds the arguments for DIB_SetImageBits() */ typedef struct { - X11DRV_PDEVICE *physDev; - LPCVOID bits; - XImage *image; - PALETTEENTRY *palentry; - int lines; - DWORD infoWidth; - WORD depth; - WORD infoBpp; - WORD compression; - RGBQUAD *colorMap; - int nColorMap; - Drawable drawable; - GC gc; - int xSrc; - int ySrc; - int xDest; - int yDest; - int width; - int height; - DWORD rMask; - DWORD gMask; - DWORD bMask; - BOOL useShm; - int dibpitch; - DWORD sizeImage; + X11DRV_PDEVICE *physDev; + LPCVOID bits; + XImage *image; + PALETTEENTRY *palentry; + int lines; + DWORD infoWidth; + WORD depth; + WORD infoBpp; + WORD compression; + RGBQUAD *colorMap; + int nColorMap; + Drawable drawable; + GC gc; + int xSrc; + int ySrc; + int xDest; + int yDest; + int width; + int height; + DWORD rMask; + DWORD gMask; + DWORD bMask; + enum x11drv_shm_mode shm_mode; + int dibpitch; + DWORD sizeImage; + X_PHYSBITMAP *physBitmap; } X11DRV_DIB_IMAGEBITS_DESCR; @@ -3532,6 +3533,7 @@ static void X11DRV_DIB_SetImageBits_GetSubImage( static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) { int lines = descr->lines >= 0 ? descr->lines : -descr->lines; + void *old_data = NULL; XImage *bmpImage; wine_tsx11_lock(); @@ -3556,6 +3558,22 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) bmpImage->depth,bmpImage->bits_per_pixel, bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask); +#ifdef HAVE_LIBXXSHM + if (descr->shm_mode == X11DRV_SHM_PIXMAP + && descr->xSrc == 0 && descr->ySrc == 0 + && descr->xDest == 0 && descr->yDest == 0) + { + TRACE("Using the shared pixmap data.\n"); + + wine_tsx11_lock(); + XSync( gdi_display, False ); + wine_tsx11_unlock(); + + old_data = descr->image->data; + descr->image->data = descr->physBitmap->shminfo.shmaddr; + } +#endif + /* Transfer the pixels */ __TRY { @@ -3635,7 +3653,13 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) if (lines) { #ifdef HAVE_LIBXXSHM - if (descr->image && descr->useShm) + if (descr->shm_mode == X11DRV_SHM_PIXMAP + && descr->xSrc == 0 && descr->ySrc == 0 + && descr->xDest == 0 && descr->yDest == 0) + { + XSync( gdi_display, False ); + } + else if (descr->shm_mode == X11DRV_SHM_IMAGE && descr->image) { XShmPutImage( gdi_display, descr->drawable, descr->gc, bmpImage, descr->xSrc, descr->ySrc, descr->xDest, descr->yDest, @@ -3644,10 +3668,15 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) } else #endif + { XPutImage( gdi_display, descr->drawable, descr->gc, bmpImage, descr->xSrc, descr->ySrc, descr->xDest, descr->yDest, descr->width, descr->height ); + } } + + if (old_data) descr->image->data = old_data; + if (!descr->image) X11DRV_DIB_DestroyXImage( bmpImage ); wine_tsx11_unlock(); return lines; @@ -3661,6 +3690,7 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) { int lines = descr->lines >= 0 ? descr->lines : -descr->lines; + void *old_data = NULL; XImage *bmpImage; wine_tsx11_lock(); @@ -3682,8 +3712,20 @@ static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) /* We must not call XShmGetImage() with a bitmap which is bigger than the available area. If we do, XShmGetImage() will fail (X exception), as it checks for this internally. */ - if((descr->image && descr->useShm) && (bmpImage->width <= (descr->width - descr->xSrc)) - && (bmpImage->height <= (descr->height - descr->ySrc))) + if (descr->shm_mode == X11DRV_SHM_PIXMAP && descr->image + && descr->xSrc == 0 && descr->ySrc == 0 + && descr->xDest == 0 && descr->yDest == 0 + && bmpImage->width <= (descr->width - descr->xSrc) + && bmpImage->height <= (descr->height - descr->ySrc)) + { + XSync( gdi_display, False ); + old_data = bmpImage->data; + bmpImage->data = descr->physBitmap->shminfo.shmaddr; + TRACE("Using shared pixmap data.\n"); + } + else if (descr->shm_mode == X11DRV_SHM_IMAGE && descr->image + && bmpImage->width <= (descr->width - descr->xSrc) + && bmpImage->height <= (descr->height - descr->ySrc)) { int saveRed, saveGreen, saveBlue; @@ -3786,6 +3828,7 @@ static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) break; } + if (old_data) bmpImage->data = old_data; if (!descr->image) X11DRV_DIB_DestroyXImage( bmpImage ); return lines; } @@ -3888,23 +3931,24 @@ INT CDECL X11DRV_SetDIBitsToDevice( X11DRV_PDEVICE *physDev, INT xDest, INT yDes break; } - descr.physDev = physDev; - descr.bits = bits; - descr.image = NULL; - descr.palentry = NULL; - descr.lines = top_down ? -lines : lines; - descr.infoWidth = width; - descr.depth = physDev->depth; - descr.drawable = physDev->drawable; - descr.gc = physDev->gc; - descr.xSrc = xSrc; - descr.ySrc = ySrc; - descr.xDest = physDev->dc_rect.left + pt.x; - descr.yDest = physDev->dc_rect.top + pt.y; - descr.width = cx; - descr.height = cy; - descr.useShm = FALSE; - descr.dibpitch = ((width * descr.infoBpp + 31) &~31) / 8; + descr.physDev = physDev; + descr.bits = bits; + descr.image = NULL; + descr.palentry = NULL; + descr.lines = top_down ? -lines : lines; + descr.infoWidth = width; + descr.depth = physDev->depth; + descr.drawable = physDev->drawable; + descr.gc = physDev->gc; + descr.xSrc = xSrc; + descr.ySrc = ySrc; + descr.xDest = physDev->dc_rect.left + pt.x; + descr.yDest = physDev->dc_rect.top + pt.y; + descr.width = cx; + descr.height = cy; + descr.shm_mode = X11DRV_SHM_NONE; + descr.dibpitch = ((width * descr.infoBpp + 31) &~31) / 8; + descr.physBitmap = NULL; result = X11DRV_DIB_SetImageBits( &descr ); @@ -3977,22 +4021,23 @@ INT CDECL X11DRV_SetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT start default: break; } - descr.bits = bits; - descr.image = NULL; - descr.palentry = NULL; - descr.infoWidth = width; - descr.lines = tmpheight >= 0 ? lines : -lines; - descr.depth = physBitmap->pixmap_depth; - descr.drawable = physBitmap->pixmap; - descr.gc = get_bitmap_gc(physBitmap->pixmap_depth); - descr.xSrc = 0; - descr.ySrc = 0; - descr.xDest = 0; - descr.yDest = height - startscan - lines; - descr.width = ds.dsBm.bmWidth; - descr.height = lines; - descr.useShm = FALSE; - descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8; + descr.bits = bits; + descr.image = NULL; + descr.palentry = NULL; + descr.infoWidth = width; + descr.lines = tmpheight >= 0 ? lines : -lines; + descr.depth = physBitmap->pixmap_depth; + descr.drawable = physBitmap->pixmap; + descr.gc = get_bitmap_gc(physBitmap->pixmap_depth); + descr.xSrc = 0; + descr.ySrc = 0; + descr.xDest = 0; + descr.yDest = height - startscan - lines; + descr.width = ds.dsBm.bmWidth; + descr.height = lines; + descr.shm_mode = X11DRV_SHM_NONE; + descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8; + descr.physBitmap = NULL; X11DRV_DIB_Lock( physBitmap, DIB_Status_GdiMod ); result = X11DRV_DIB_SetImageBits( &descr ); @@ -4130,21 +4175,22 @@ INT CDECL X11DRV_GetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT start break; } - descr.physDev = physDev; - descr.palentry = palette; - descr.bits = bits; - descr.image = physBitmap->image; - descr.infoWidth = width; - descr.lines = lines; - descr.depth = physBitmap->pixmap_depth; - descr.drawable = physBitmap->pixmap; - descr.gc = get_bitmap_gc(physBitmap->pixmap_depth); - descr.width = dib.dsBm.bmWidth; - descr.height = dib.dsBm.bmHeight; - descr.xDest = 0; - descr.yDest = 0; - descr.xSrc = 0; - descr.sizeImage = core_header ? 0 : info->bmiHeader.biSizeImage; + descr.physDev = physDev; + descr.palentry = palette; + descr.bits = bits; + descr.image = physBitmap->image; + descr.infoWidth = width; + descr.lines = lines; + descr.depth = physBitmap->pixmap_depth; + descr.drawable = physBitmap->pixmap; + descr.gc = get_bitmap_gc(physBitmap->pixmap_depth); + descr.width = dib.dsBm.bmWidth; + descr.height = dib.dsBm.bmHeight; + descr.xDest = 0; + descr.yDest = 0; + descr.xSrc = 0; + descr.sizeImage = core_header ? 0 : info->bmiHeader.biSizeImage; + descr.physBitmap = physBitmap; if (descr.lines > 0) { @@ -4154,11 +4200,7 @@ INT CDECL X11DRV_GetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT start { descr.ySrc = startscan; } -#ifdef HAVE_LIBXXSHM - descr.useShm = (obj_size == sizeof(DIBSECTION)) && (physBitmap->shminfo.shmid != -1); -#else - descr.useShm = FALSE; -#endif + descr.shm_mode = physBitmap->shm_mode; descr.dibpitch = (obj_size == sizeof(DIBSECTION)) ? dib.dsBm.bmWidthBytes : (((descr.infoWidth * descr.infoBpp + 31) &~31) / 8); @@ -4205,17 +4247,18 @@ static void X11DRV_DIB_DoCopyDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB, if (!GetObjectW( physBitmap->hbitmap, sizeof(dibSection), &dibSection )) return; - descr.physDev = NULL; - descr.palentry = NULL; - descr.infoWidth = dibSection.dsBmih.biWidth; - descr.infoBpp = dibSection.dsBmih.biBitCount; - descr.lines = dibSection.dsBmih.biHeight; - descr.image = physBitmap->image; - descr.colorMap = colorMap; - descr.nColorMap = nColorMap; - descr.bits = dibSection.dsBm.bmBits; - descr.depth = physBitmap->pixmap_depth; + descr.physDev = NULL; + descr.palentry = NULL; + descr.infoWidth = dibSection.dsBmih.biWidth; + descr.infoBpp = dibSection.dsBmih.biBitCount; + descr.lines = dibSection.dsBmih.biHeight; + descr.image = physBitmap->image; + descr.colorMap = colorMap; + descr.nColorMap = nColorMap; + descr.bits = dibSection.dsBm.bmBits; + descr.depth = physBitmap->pixmap_depth; descr.compression = dibSection.dsBmih.biCompression; + descr.physBitmap = physBitmap; if(descr.infoBpp == 1) descr.colorMap = (void*)identity; @@ -4253,10 +4296,12 @@ static void X11DRV_DIB_DoCopyDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB, descr.height = height; descr.sizeImage = 0; + descr.shm_mode = physBitmap->shm_mode; #ifdef HAVE_LIBXXSHM - descr.useShm = (physBitmap->shminfo.shmid != -1); -#else - descr.useShm = FALSE; + if (physBitmap->shm_mode == X11DRV_SHM_PIXMAP && physBitmap->pixmap != dest) + { + descr.shm_mode = X11DRV_SHM_IMAGE; + } #endif descr.dibpitch = dibSection.dsBm.bmWidthBytes; @@ -4645,7 +4690,7 @@ static XImage *X11DRV_XShmCreateImage( int width, int height, int bpp, IPC_CREAT|0700); if( shminfo->shmid != -1 ) { - shminfo->shmaddr = image->data = shmat(shminfo->shmid, 0, 0); + shminfo->shmaddr = shmat( shminfo->shmid, 0, 0 ); if( shminfo->shmaddr != (char*)-1 ) { BOOL ok; @@ -4683,6 +4728,10 @@ HBITMAP CDECL X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, { X_PHYSBITMAP *physBitmap; DIBSECTION dib; +#ifdef HAVE_LIBXXSHM + int major, minor; + Bool pixmaps; +#endif if (!(physBitmap = X11DRV_init_phys_bitmap( hbitmap ))) return 0; physBitmap->status = DIB_Status_None; @@ -4700,16 +4749,49 @@ HBITMAP CDECL X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, /* create pixmap and X image */ wine_tsx11_lock(); physBitmap->pixmap_depth = (dib.dsBm.bmBitsPixel == 1) ? 1 : screen_depth; - physBitmap->pixmap = XCreatePixmap( gdi_display, root_window, dib.dsBm.bmWidth, - dib.dsBm.bmHeight, physBitmap->pixmap_depth ); #ifdef HAVE_LIBXXSHM physBitmap->shminfo.shmid = -1; - if (!XShmQueryExtension(gdi_display) || - !(physBitmap->image = X11DRV_XShmCreateImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight, - physBitmap->pixmap_depth, &physBitmap->shminfo )) ) + + if (XShmQueryVersion( gdi_display, &major, &minor, &pixmaps ) + && (physBitmap->image = X11DRV_XShmCreateImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight, + physBitmap->pixmap_depth, &physBitmap->shminfo ))) + { + if (pixmaps) + { + physBitmap->shm_mode = X11DRV_SHM_PIXMAP; + physBitmap->image->data = HeapAlloc( GetProcessHeap(), 0, + dib.dsBm.bmHeight * physBitmap->image->bytes_per_line ); + } + else + { + physBitmap->shm_mode = X11DRV_SHM_IMAGE; + physBitmap->image->data = physBitmap->shminfo.shmaddr; + } + } + else #endif + { + physBitmap->shm_mode = X11DRV_SHM_NONE; physBitmap->image = X11DRV_DIB_CreateXImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight, physBitmap->pixmap_depth ); + } + +#ifdef HAVE_LIBXXSHM + if (physBitmap->shm_mode == X11DRV_SHM_PIXMAP) + { + TRACE("Creating shared pixmap for bmp %p.\n", physBitmap->hbitmap); + physBitmap->pixmap = XShmCreatePixmap( gdi_display, root_window, + physBitmap->shminfo.shmaddr, &physBitmap->shminfo, + dib.dsBm.bmWidth, dib.dsBm.bmHeight, + physBitmap->pixmap_depth ); + } + else +#endif + { + physBitmap->pixmap = XCreatePixmap( gdi_display, root_window, dib.dsBm.bmWidth, + dib.dsBm.bmHeight, physBitmap->pixmap_depth ); + } + wine_tsx11_unlock(); if (!physBitmap->pixmap || !physBitmap->image) return 0; @@ -4760,9 +4842,11 @@ void X11DRV_DIB_DeleteDIBSection(X_PHYSBITMAP *physBitmap, DIBSECTION *dib) if (physBitmap->shminfo.shmid != -1) { XShmDetach( gdi_display, &(physBitmap->shminfo) ); - XDestroyImage( physBitmap->image ); + if (physBitmap->shm_mode == X11DRV_SHM_PIXMAP) X11DRV_DIB_DestroyXImage( physBitmap->image ); + else XDestroyImage( physBitmap->image ); shmdt( physBitmap->shminfo.shmaddr ); physBitmap->shminfo.shmid = -1; + physBitmap->shm_mode = X11DRV_SHM_NONE; } else #endif diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1a7a634f43e..26671ebfefe 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -92,6 +92,13 @@ typedef struct Pixmap pixmap; } X_PHYSBRUSH; +enum x11drv_shm_mode +{ + X11DRV_SHM_NONE = 0, + X11DRV_SHM_PIXMAP, + X11DRV_SHM_IMAGE, +}; + /* X physical bitmap */ typedef struct { @@ -105,6 +112,7 @@ typedef struct int *colorMap; /* color map info */ int nColorMap; CRITICAL_SECTION lock; /* GDI access lock */ + enum x11drv_shm_mode shm_mode; #ifdef HAVE_LIBXXSHM XShmSegmentInfo shminfo; /* shared memory segment info */ #endif