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

On Sat, Jul 25, 2009 at 11:20 PM, Jesse Allen<the3dfxd...@gmail.com> wrote:
> On Thu, Jul 23, 2009 at 2:51 PM, Roderick
> Colenbrander<thunderbir...@gmail.com> wrote:
>> Hi,
>>
>> For some weeks I have been working on moving more 2D rendering to
>> XRender. XRender has three advantages for Wine. First of all it allows
>> us to perform more rendering operations using X which we previously
>> did using a combination of software rendering and back-forth copying
>> between the Xserver. Second XRender offers depth conversion (this
>> gives us proper alpha support in Wine and allows us to bypass DIB
>> color conversion in some cases!). Third XRender brings us more
>> hardware acceleration and that way more performance.
>>
>> The patch attached to this thread adds support for dibsections in
>> additional color depths. On Xservers running at 24-bit this patch
>> offers us dibsections in 1-bit/15-bit/16-bit/24-bit/32-bit. (32-bit is
>> for proper alpha support) Big parts of the Wine X11 Driver make
>> assumptions about having only two color depths around (1-bit and
>> screen_depth e.g. 24-bit). I would like to request that people apply
>> the current patch to latest git (in combination with the Office2007
>> patch which I posted to wine-patches). Please report any 2D rendering
>> issues you see and also mention possible Wine crashes due to X errors
>> like BadMatch. Try as much programs as possible.
>>
>> Thanks in advance,
>> Roderick Colenbrander
>>
>>
>>
>>
>
>
>
> Very nice Roderick,  it seems to be working on my system with
> StarEdit.exe where it is faster.  It seems like it could be a good
> solution.
>
> Jesse
>
From 80f7325253f8b38750398daf044f7c6e32f772e1 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   |   16 +++--
 dlls/winex11.drv/dib.c     |   11 +++-
 dlls/winex11.drv/x11drv.h  |    1 +
 dlls/winex11.drv/xrender.c |  140 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 161 insertions(+), 8 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..37d5e1f 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,26 @@ 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
     {
         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 );
+                                               physDev->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 +262,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..fef6b60 100644
--- a/dlls/winex11.drv/xrender.c
+++ b/dlls/winex11.drv/xrender.c
@@ -427,10 +427,81 @@ 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) )
+
+        {
+            /* 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 +888,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
  *
@@ -2058,6 +2159,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)
+    {
+        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 +2221,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