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
From 1ffe94b441654ba146cfe2fd10965b4aed43c03c Mon Sep 17 00:00:00 2001
From: Roderick Colenbrander <roder...@roderick-laptop.(none)>
Date: Sun, 19 Jul 2009 18:44:21 +0200
Subject: [PATCH] Add support for dibsections in depths other than 1-bit / screen_depth when XRender is around.
---
dlls/winex11.drv/dib.c | 11 +++++-
dlls/winex11.drv/x11drv.h | 1 +
dlls/winex11.drv/xrender.c | 84 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+), 1 deletions(-)
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 10af183..65a3a89 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 xSrc, INT ySrc,
diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c
index 3bf37e4..31b9ce7 100644
--- a/dlls/winex11.drv/xrender.c
+++ b/dlls/winex11.drv/xrender.c
@@ -427,10 +427,55 @@ 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_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 +862,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
*
@@ -2108,6 +2183,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