Hi all, This is an updated version of the patch which also addresses the font color issue in that japanese game. I hope as much people can test it so that I can fix other potential bugs (hopefully there are none left).
Roderick On Tue, Jul 28, 2009 at 12:25 AM, Roderick Colenbrander<thunderbir...@gmail.com> wrote: > Hi, > > This version should hopefully fix your issues. I hope it also fixes > other gc issues .. I'm not sure if the patch is correct yet though. > > Roderick > > On Mon, Jul 27, 2009 at 11:08 AM, Matej > Spindler<spindler.ma...@gmail.com> wrote: >> Roderick Colenbrander wrote: >>> >>> Hi all, >>> >>> This is an updated version of my patch. It should fix the XChangeGC >>> crash but the text color issue in that japanese game is still around. >>> I hope to receive some more feed back. >>> >>> Roderick >>> >> >> Hi Roderick >> >> With this patch Room Arranger crashes with: >>> >>> X Error of failed request: BadMatch (invalid parameter attributes) >>> Major opcode of failed request: 56 (X_ChangeGC) >>> Serial number of failed request: 18560 >>> Current serial number in output stream: 18919 >> >> Program can be downloaded from: http://www.roomarranger.com/ >> >> Matej >> >> >> >
From c202729ee60f45b4a136dbbc1bef2a2685bd26a2 Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander <thunderbir...@gmail.com> Date: Sun, 26 Jul 2009 22:35:59 +0200 Subject: [PATCH] Add support for dibsections in more formats when XRender is around. --- dlls/winex11.drv/bitmap.c | 1 + dlls/winex11.drv/brush.c | 18 +++-- dlls/winex11.drv/dib.c | 11 +++- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/xrender.c | 148 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 169 insertions(+), 10 deletions(-) diff --git a/dlls/winex11.drv/bitmap.c b/dlls/winex11.drv/bitmap.c index a288352..03e78a0 100644 --- a/dlls/winex11.drv/bitmap.c +++ b/dlls/winex11.drv/bitmap.c @@ -161,6 +161,7 @@ BOOL CDECL X11DRV_CreateBitmap( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, LPVOID physBitmap->pixmap_depth = (bitmap.bmBitsPixel == 1) ? 1 : screen_depth; physBitmap->pixmap = XCreatePixmap(gdi_display, root_window, bitmap.bmWidth, bitmap.bmHeight, physBitmap->pixmap_depth); +//ERR("hbitmap=%p pixmap_depth=%d pixmap=%p\n", hbitmap, physBitmap->pixmap_depth, physBitmap->pixmap); wine_tsx11_unlock(); if (!physBitmap->pixmap) { diff --git a/dlls/winex11.drv/brush.c b/dlls/winex11.drv/brush.c index c94e04e..8621565 100644 --- a/dlls/winex11.drv/brush.c +++ b/dlls/winex11.drv/brush.c @@ -204,7 +204,8 @@ static void BRUSH_SelectSolidBrush( X11DRV_PDEVICE *physDev, COLORREF color ) } } - +//this will be moved to x11drv.h later on +BOOL X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height); /*********************************************************************** * BRUSH_SelectPatternBrush */ @@ -215,25 +216,28 @@ static BOOL BRUSH_SelectPatternBrush( X11DRV_PDEVICE *physDev, HBITMAP hbitmap ) if (!physBitmap || !GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE; - wine_tsx11_lock(); if ((physDev->depth == 1) && (physBitmap->pixmap_depth != 1)) { + wine_tsx11_lock(); /* Special case: a color pattern on a monochrome DC */ physDev->brush.pixmap = XCreatePixmap( gdi_display, root_window, bitmap.bmWidth, bitmap.bmHeight, 1); /* FIXME: should probably convert to monochrome instead */ XCopyPlane( gdi_display, physBitmap->pixmap, physDev->brush.pixmap, get_bitmap_gc(1), 0, 0, bitmap.bmWidth, bitmap.bmHeight, 0, 0, 1 ); + wine_tsx11_unlock(); } else { + int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth; //is this correct? room architect else triggers some fun gc depth mismatch issues +//ERR("%d %d\n", physBitmap->pixmap_depth, physDev->depth); physDev->brush.pixmap = XCreatePixmap( gdi_display, root_window, bitmap.bmWidth, bitmap.bmHeight, - physBitmap->pixmap_depth ); - XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap, - get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, bitmap.bmWidth, bitmap.bmHeight, 0, 0 ); + depth); + + /* XRender is needed because of possible depth conversion */ + X11DRV_XRender_CopyBrush(physDev, physBitmap, bitmap.bmWidth, bitmap.bmHeight); } - wine_tsx11_unlock(); if (physBitmap->pixmap_depth > 1) { @@ -260,7 +264,7 @@ HBRUSH CDECL X11DRV_SelectBrush( X11DRV_PDEVICE *physDev, HBRUSH hbrush ) if (!GetObjectA( hbrush, sizeof(logbrush), &logbrush )) return 0; - TRACE("hdc=%p hbrush=%p\n", physDev->hdc,hbrush); + TRACE("hdc=%p hbrush=%p style=%x\n", physDev->hdc,hbrush, logbrush.lbStyle); if (physDev->brush.pixmap) { diff --git a/dlls/winex11.drv/dib.c b/dlls/winex11.drv/dib.c index 07ce9e1..3e88cbe 100644 --- a/dlls/winex11.drv/dib.c +++ b/dlls/winex11.drv/dib.c @@ -4683,6 +4683,7 @@ HBITMAP CDECL X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, { X_PHYSBITMAP *physBitmap; DIBSECTION dib; + int redMask, greenMask, blueMask; if (!(physBitmap = X11DRV_init_phys_bitmap( hbitmap ))) return 0; physBitmap->status = DIB_Status_None; @@ -4699,7 +4700,7 @@ 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_depth = X11DRV_XRender_GetDIBDepth(&dib, &redMask, &greenMask, &blueMask); physBitmap->pixmap = XCreatePixmap( gdi_display, root_window, dib.dsBm.bmWidth, dib.dsBm.bmHeight, physBitmap->pixmap_depth ); #ifdef HAVE_LIBXXSHM @@ -4713,6 +4714,14 @@ HBITMAP CDECL X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, wine_tsx11_unlock(); if (!physBitmap->pixmap || !physBitmap->image) return 0; + /* When XRender is around and used, we also support dibsections in other formats like 16-bit. In these + * cases we need to override the mask of XImages. The reason is that during XImage creation the masks are + * derived from a 24-bit visual (no 16-bit ones are around when X runs at 24-bit). SetImageBits and other + * functions rely on the color masks for proper color conversion, so we need to override the masks here. */ + physBitmap->image->red_mask = redMask; + physBitmap->image->green_mask = greenMask; + physBitmap->image->blue_mask = blueMask; + /* install fault handler */ InitializeCriticalSection( &physBitmap->lock ); physBitmap->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": X_PHYSBITMAP.lock"); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1a7a634..5f39fe6 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -267,6 +267,7 @@ extern void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE*); extern BOOL X11DRV_XRender_ExtTextOut(X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags, const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx); +extern int X11DRV_XRender_GetDIBDepth(const DIBSECTION *dib, int *redMask, int *greenMask, int *blueMask); BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst, Pixmap pixmap, GC gc, INT widthSrc, INT heightSrc, diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c index 072cd25..0fe7035 100644 --- a/dlls/winex11.drv/xrender.c +++ b/dlls/winex11.drv/xrender.c @@ -427,10 +427,82 @@ static WineXRenderFormat *get_xrender_format(WXRFormat format) return NULL; } +static WineXRenderFormat *get_xrender_format_from_dibsection(const DIBSECTION *dib) +{ + int redMask=0, greenMask=0, blueMask=0; + int i; + + if(dib->dsBm.bmBitsPixel == 1) + return get_xrender_format(WXR_FORMAT_MONO); + + /* Paletted formats aren't supported using XRender */ + if(dib->dsBm.bmBitsPixel <= 8) + return NULL; + + redMask = dib->dsBitfields[0]; + greenMask = dib->dsBitfields[1]; + blueMask = dib->dsBitfields[2]; + + /* Try to locate a format which matches the specification of the dibsection. */ + for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++) + { + if( dib->dsBm.bmBitsPixel == wxr_formats_template[i].depth && + redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) && + greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) && + blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) && + 0 == (wxr_formats_template[i].alphaMask << wxr_formats_template[i].alpha) ) + + { + /* When we reach this stage the format was found in our template table but this doesn't mean that + * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that. + */ + return get_xrender_format(wxr_formats_template[i].wxr_format); + } + } + + /* Format not found */ + return NULL; +} + +static WineXRenderFormat *get_xrender_format_from_pbitmap(X_PHYSBITMAP *physBitmap) +{ + DIBSECTION dib; + + /* When the physdev is associated with a dibsection, use get_xrender_from_dibsection */ + if (GetObjectW( physBitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib)) + { + WineXRenderFormat *fmt = get_xrender_format_from_dibsection(&dib); + if(fmt) return fmt; + } + + /* We are dealing with a DIB in a format for which conversion is required or with a DDB / window */ + switch(physBitmap->pixmap_depth) + { + case 1: + return get_xrender_format(WXR_FORMAT_MONO); + + default: + /* For now fall back to the format of the default visual. + In the future we should check if we are using a DDB/DIB and what exact format we need. + */ + return default_format; + } +} + + static WineXRenderFormat *get_xrender_format_from_pdevice(X11DRV_PDEVICE *physDev) { WXRFormat format; + DIBSECTION dib; + + /* When the physdev is associated with a dibsection, use get_xrender_from_dibsection */ + if (physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib)) + { + WineXRenderFormat *fmt = get_xrender_format_from_dibsection(&dib); + if(fmt) return fmt; + } + /* We are dealing with a DIB in a format for which conversion is required or with a DDB / window */ switch(physDev->depth) { case 1: @@ -817,6 +889,36 @@ void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev) return; } +int X11DRV_XRender_GetDIBDepth(const DIBSECTION *dib, int *redMask, int *greenMask, int *blueMask) +{ + WineXRenderFormat *fmt; + + /* By default derive the masks from the default visual */ + *redMask = visual->red_mask; + *greenMask = visual->green_mask; + *blueMask = visual->blue_mask; + + /* Fall back to the generic code when XRender isn't around */ + if(!X11DRV_XRender_Installed) + return (dib->dsBm.bmBitsPixel == 1) ? 1 : screen_depth; + + /* Common formats should be in our picture format table. If a format isn't around + * fall back to 1-bit / screen_depth. */ + fmt = get_xrender_format_from_dibsection(dib); + if(fmt) + { + *redMask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red; + *greenMask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green; + *blueMask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue; + return fmt->pict_format->depth; + } + else + { + WARN("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n", dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]); + return (dib->dsBm.bmBitsPixel == 1) ? 1 : screen_depth; + } +} + /*********************************************************************** * X11DRV_XRender_UpdateDrawable * @@ -1346,7 +1448,9 @@ static Picture get_tile_pict(WineXRenderFormat *wxr_format, int text_pixel) if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO) { - get_xrender_color(wxr_format, text_pixel, &col); + /* text_pixel is in R8G8B8 */ + get_xrender_color(get_xrender_format(WXR_FORMAT_R8G8B8), text_pixel, &col); + wine_tsx11_lock(); pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1); wine_tsx11_unlock(); @@ -2019,7 +2123,8 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE if(physDevSrc->depth == 1) { XRenderColor col; - get_xrender_color(dst_format, physDevDst->textPixel, &col); + /* textPixel is in R8G8B8 */ + get_xrender_color(get_xrender_format(WXR_FORMAT_R8G8B8), physDevDst->textPixel, &col); /* We use the source drawable as a mask */ wine_tsx11_lock(); @@ -2058,6 +2163,36 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE return TRUE; } +void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height) +{ + wine_tsx11_lock(); + if(physDev->depth == physBitmap->pixmap_depth || physBitmap->pixmap_depth == 1) //this also isn't correct I think .. I guess we should check the brush its depth + { + XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap, + get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 ); + } + else + { + WineXRenderFormat *src_format = get_xrender_format_from_pbitmap(physBitmap); + WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(physDev); + + Picture src_pict, dst_pict; + XRenderPictureAttributes pa; + pa.subwindow_mode = IncludeInferiors; + pa.repeat = RepeatNone; + + src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa); + dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa); + +// ERR("depth mismatch src_format=%#x dst_format=%#x\n", src_format->format, dst_format->format); + // ERR("src_pict = %#lx, dst_pict = %#lx\n", src_pict, dst_pict); + xrender_blit(src_pict, 0, dst_pict, 0, 0, 1.0, 1.0, width, height); + pXRenderFreePicture(gdi_display, src_pict); + pXRenderFreePicture(gdi_display, dst_pict); + } + wine_tsx11_unlock(); +} + #else /* SONAME_LIBXRENDER */ void X11DRV_XRender_Init(void) @@ -2090,6 +2225,15 @@ BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flag return FALSE; } +int X11DRV_XRender_GetDIBDepth(const DIBSECTION *dib, int *redMask, int *greenMask, int *blueMask) +{ + /* By default derive the masks from the default visual */ + *redMask = visual->red_mask; + *greenMask = visual->green_mask; + *blueMask = visual->blue_mask; + return (dib->dsBm.bmBitsPixel == 1) ? 1 : screen_depth; +} + void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev) { assert(0); -- 1.6.0.4