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



Reply via email to