On Fri, Jul 31, 2009 at 9:25 AM, Austin English<austinengl...@gmail.com> wrote:
> On Thu, Jul 23, 2009 at 3: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
>>
>>
>>
>>
>
> Still fails the gimp test in appinstall. It's just this patch on top
> of git, nothing else right?
>
> --
> -Austin
>

Yeah it is just this patch on top of git. At what point does gimp fail
for you? I tried to open some images including the png gimp splash
screen and I'm seeing no issues. To be certain that you are using the
right patch I have reattached it (this time with the white space
trailing issues fixed). Just to be sure what display drivers are you
using and what videocard?

Roderick
From 5cbb96d0d7268a2cb68574120eb00ef6d660f545 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..f72d597 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