From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/bitblt.c | 84 ++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 15 deletions(-)
diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 7390f294d19..8e928bd491c 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1572,6 +1572,7 @@ DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo
struct x11drv_image { + BOOL byteswap; XImage *ximage; /* XImage used for X11 drawing */ void *data; /* pixels allocated for XImage */ #ifdef HAVE_LIBXXSHM @@ -1585,7 +1586,7 @@ struct x11drv_window_surface Window window; GC gc; struct x11drv_image *image; - BOOL byteswap; + HBITMAP bitmap; /* bitmap exposed to win32u */ BOOL is_argb; DWORD alpha_bits; COLORREF color_key; @@ -1829,6 +1830,29 @@ failed: } #endif /* HAVE_LIBXXSHM */
+static UINT d3dddifmt_from_mask( const BITMAPINFO *info ) +{ + if (info->bmiHeader.biCompression == BI_RGB) + { + if (info->bmiHeader.biBitCount == 8) return D3DDDIFMT_P8; + if (info->bmiHeader.biBitCount == 24) return D3DDDIFMT_R8G8B8; + if (info->bmiHeader.biBitCount == 32) return D3DDDIFMT_A8R8G8B8; + return D3DDDIFMT_UNKNOWN; + } + + if (info->bmiHeader.biCompression == BI_BITFIELDS) + { + DWORD *colors = (DWORD *)info->bmiColors; + if (info->bmiHeader.biBitCount != 16) return D3DDDIFMT_UNKNOWN; + if (colors[0] == 0x0000f800 && colors[1] == 0x000007e0 && colors[2] == 0x0000001f) return D3DDDIFMT_R5G6B5; + if (colors[0] == 0x00007c00 && colors[1] == 0x000003e0 && colors[2] == 0x0000001f) return D3DDDIFMT_A1R5G5B5; + if (colors[0] == 0x00000f00 && colors[1] == 0x000000f0 && colors[2] == 0x0000000f) return D3DDDIFMT_A4R4G4B4; + return D3DDDIFMT_UNKNOWN; + } + + return D3DDDIFMT_UNKNOWN; +} + static void x11drv_image_destroy( struct x11drv_image *image ) { #ifdef HAVE_LIBXXSHM @@ -1846,9 +1870,10 @@ static void x11drv_image_destroy( struct x11drv_image *image ) free( image->data ); }
-static struct x11drv_image *x11drv_image_create( const BITMAPINFO *info, const XVisualInfo *vis ) +static struct x11drv_image *x11drv_image_create( const BITMAPINFO *info, const XVisualInfo *vis, HBITMAP *bitmap ) { struct x11drv_image *image; + void *bits;
if (!(image = calloc( 1, sizeof(*image) ))) return NULL; #ifdef HAVE_LIBXXSHM @@ -1858,12 +1883,46 @@ static struct x11drv_image *x11drv_image_create( const BITMAPINFO *info, const X info->bmiHeader.biWidth, abs( info->bmiHeader.biHeight ), 32, 0 ); if (!image->ximage) goto failed;
+ /* wrap the XImage in a HBITMAP if we can write the surface pixels directly */ + if (!(image->byteswap = image_needs_byteswap( image->ximage, is_r8g8b8( vis ), info->bmiHeader.biBitCount )) && + info->bmiHeader.biBitCount > 8) + { + D3DDDIFORMAT format; + + if (!(bits = image->ximage->data)) *bitmap = NtGdiCreateDIBSection( 0, NULL, 0, info, DIB_RGB_COLORS, 0, 0, 0, &bits ); + else if ((format = d3dddifmt_from_mask( info ))) + { + D3DKMT_CREATEDCFROMMEMORY desc = + { + .Width = info->bmiHeader.biWidth, + .Height = info->bmiHeader.biHeight, + .Pitch = info->bmiHeader.biWidth * info->bmiHeader.biBitCount / 8, + .Format = format, + .pMemory = bits, + }; + + if (!NtGdiDdDDICreateDCFromMemory( &desc )) + { + *bitmap = desc.hBitmap; + NtGdiDeleteObjectApp( desc.hDc ); + } + } + + image->ximage->data = bits; + } + + /* allocate a separate storage otherwise to perform color conversion on flush */ if (!image->ximage->data) image->ximage->data = image->data = malloc( info->bmiHeader.biSizeImage ); if (!image->ximage->data) goto failed; + + if (!*bitmap) *bitmap = NtGdiCreateDIBSection( 0, NULL, 0, info, DIB_RGB_COLORS, 0, 0, 0, &bits ); + if (!*bitmap) goto failed; + return image;
failed: if (image) XDestroyImage( image->ximage ); + if (image) free( image->data ); free( image ); return NULL; } @@ -1936,7 +1995,7 @@ static BOOL x11drv_surface_flush( struct window_surface *window_surface, const R src += dirty->top * width_bytes; dst += dirty->top * width_bytes; copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes, dirty->bottom - dirty->top, - surface->byteswap, mapping, ~0u, surface->alpha_bits ); + surface->image->byteswap, mapping, ~0u, surface->alpha_bits ); } else if (surface->alpha_bits) { @@ -1973,6 +2032,7 @@ static void x11drv_surface_destroy( struct window_surface *window_surface ) TRACE( "freeing %p bits %p\n", surface, window_surface->color_bits ); if (surface->gc) XFreeGC( gdi_display, surface->gc ); if (surface->image) x11drv_image_destroy( surface->image ); + if (surface->bitmap) NtGdiDeleteObjectApp( surface->bitmap ); free( surface ); }
@@ -1997,6 +2057,7 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn int width = rect->right - rect->left, height = rect->bottom - rect->top; int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3; struct x11drv_image *image; + HBITMAP bitmap = 0; UINT size;
info->bmiHeader.biSize = sizeof(info->bmiHeader); @@ -2008,15 +2069,17 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn if (format->bits_per_pixel > 8) set_color_info( vis, info, use_alpha );
size = FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ); - if (!(image = x11drv_image_create( info, vis ))) return NULL; + if (!(image = x11drv_image_create( info, vis, &bitmap ))) return NULL; if (!(surface = calloc( 1, size ))) { + if (bitmap) NtGdiDeleteObjectApp( bitmap ); x11drv_image_destroy( image ); return NULL; } surface->image = image; + surface->bitmap = bitmap;
- if (!window_surface_init( &surface->header, &x11drv_surface_funcs, hwnd, info, 0 )) goto failed; + if (!window_surface_init( &surface->header, &x11drv_surface_funcs, hwnd, info, bitmap )) goto failed; memcpy( &surface->info, info, get_dib_info_size( info, DIB_RGB_COLORS ) );
surface->window = window; @@ -2025,20 +2088,11 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn
surface->gc = XCreateGC( gdi_display, window, 0, NULL ); XSetSubwindowMode( gdi_display, surface->gc, IncludeInferiors ); - surface->byteswap = image_needs_byteswap( surface->image->ximage, is_r8g8b8(vis), format->bits_per_pixel );
if (vis->depth == 32 && !surface->is_argb) surface->alpha_bits = ~(vis->red_mask | vis->green_mask | vis->blue_mask);
- if (surface->byteswap || format->bits_per_pixel == 4 || format->bits_per_pixel == 8) - { - /* allocate separate surface bits if byte swapping or palette mapping is required */ - if (!(surface->header.color_bits = calloc( 1, info->bmiHeader.biSizeImage ))) - goto failed; - } - else surface->header.color_bits = surface->image->ximage->data; - - TRACE( "created %p for %lx %s color_bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect), + TRACE( "created %p for %lx %s bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect), surface->header.color_bits, (char *)surface->header.color_bits + info->bmiHeader.biSizeImage, surface->image->ximage->data );