This should help unifying the interface and get rid of the get_info callback.
Later, I think we could create bitmaps over sections shared with some DWM process and/or host compositor.
-- v2: win32u: Create a HBITMAP backing the window surface pixels. winex11: Create a HBITMAP for the allocated surface pixels. winex11: Create XImage before initializing the window surface. win32u: Pass BITMAPINFO and a HBITMAP to window_surface_init. win32u: Move the window surface color bits to the common struct.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 5 ++--- dlls/wineandroid.drv/window.c | 15 +++++++------- dlls/winemac.drv/surface.c | 21 +++++++++---------- dlls/winewayland.drv/window_surface.c | 28 ++++++++++++-------------- dlls/winex11.drv/bitblt.c | 29 +++++++++++++-------------- include/wine/gdi_driver.h | 5 +++-- 6 files changed, 49 insertions(+), 54 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 02b11db4dd5..6bb090cedcf 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -113,7 +113,6 @@ struct window_surface dummy_surface = struct offscreen_window_surface { struct window_surface header; - char *bits; BITMAPINFO info; };
@@ -129,7 +128,7 @@ static void *offscreen_window_surface_get_bitmap_info( struct window_surface *ba { struct offscreen_window_surface *impl = impl_from_window_surface( base ); info->bmiHeader = impl->info.bmiHeader; - return impl->bits; + return base->color_bits; }
static void offscreen_window_surface_set_clip( struct window_surface *base, const RECT *rects, UINT count ) @@ -182,7 +181,7 @@ void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struc if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return; window_surface_init( &impl->header, &offscreen_window_surface_funcs, hwnd, &surface_rect );
- impl->bits = (char *)&impl->info.bmiColors[0]; + impl->header.color_bits = (char *)&impl->info.bmiColors[0]; impl->info.bmiHeader.biSize = sizeof( impl->info ); impl->info.bmiHeader.biWidth = surface_rect.right; impl->info.bmiHeader.biHeight = surface_rect.bottom; diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index de1de330181..657a5ff62cc 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -575,7 +575,6 @@ struct android_window_surface RECT *clip_rects; BYTE alpha; COLORREF color_key; - void *bits; BITMAPINFO info; /* variable size, must be last */ };
@@ -643,7 +642,7 @@ static void *android_surface_get_bitmap_info( struct window_surface *window_surf struct android_window_surface *surface = get_android_surface( window_surface );
memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS )); - return surface->bits; + return window_surface->color_bits; }
/*********************************************************************** @@ -688,7 +687,7 @@ static BOOL android_surface_flush( struct window_surface *window_surface, const locked.bottom = rc.bottom; intersect_rect( &locked, &locked, rect );
- src = (DWORD *)surface->bits + (locked.top - rect->top) * surface->info.bmiHeader.biWidth + + src = (DWORD *)window_surface->color_bits + (locked.top - rect->top) * surface->info.bmiHeader.biWidth + (locked.left - rect->left); dst = (DWORD *)buffer.bits + locked.top * buffer.stride + locked.left; width = min( locked.right - locked.left, buffer.stride ); @@ -733,11 +732,11 @@ static void android_surface_destroy( struct window_surface *window_surface ) { struct android_window_surface *surface = get_android_surface( window_surface );
- TRACE( "freeing %p bits %p\n", surface, surface->bits ); + TRACE( "freeing %p bits %p\n", surface, window_surface->color_bits );
free( surface->clip_rects ); release_ioctl_window( surface->window ); - free( surface->bits ); + free( window_surface->color_bits ); free( surface ); }
@@ -797,11 +796,11 @@ static struct window_surface *create_surface( HWND hwnd, const RECT *rect, surface->alpha = alpha; set_color_key( surface, color_key );
- if (!(surface->bits = malloc( surface->info.bmiHeader.biSizeImage ))) + if (!(surface->header.color_bits = malloc( surface->info.bmiHeader.biSizeImage ))) goto failed;
- TRACE( "created %p hwnd %p %s bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect), - surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage ); + TRACE( "created %p hwnd %p %s color_bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect), + surface->header.color_bits, (char *)surface->header.color_bits + surface->info.bmiHeader.biSizeImage );
return &surface->header;
diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index 285561e6d02..a34df22397a 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -65,7 +65,6 @@ struct macdrv_window_surface struct window_surface header; macdrv_window window; BOOL use_alpha; - BYTE *bits; BITMAPINFO info; /* variable size, must be last */ };
@@ -80,7 +79,7 @@ static void *macdrv_surface_get_bitmap_info(struct window_surface *window_surfac struct macdrv_window_surface *surface = get_mac_surface(window_surface);
memcpy(info, &surface->info, get_dib_info_size(&surface->info, DIB_RGB_COLORS)); - return surface->bits; + return window_surface->color_bits; }
/*********************************************************************** @@ -107,8 +106,8 @@ static void macdrv_surface_destroy(struct window_surface *window_surface) { struct macdrv_window_surface *surface = get_mac_surface(window_surface);
- TRACE("freeing %p bits %p\n", surface, surface->bits); - free(surface->bits); + TRACE("freeing %p bits %p\n", surface, window_surface->color_bits); + free(window_surface->color_bits); free(surface); }
@@ -158,13 +157,13 @@ struct window_surface *create_surface(HWND hwnd, macdrv_window window, const REC surface->window = window; if (old_surface) surface->header.bounds = old_surface->bounds; surface->use_alpha = use_alpha; - surface->bits = malloc(surface->info.bmiHeader.biSizeImage); - if (!surface->bits) goto failed; + surface->header.color_bits = malloc(surface->info.bmiHeader.biSizeImage); + if (!surface->header.color_bits) goto failed; window_background = macdrv_window_background_color(); - memset_pattern4(surface->bits, &window_background, surface->info.bmiHeader.biSizeImage); + memset_pattern4(surface->header.color_bits, &window_background, surface->info.bmiHeader.biSizeImage);
- TRACE("created %p for %p %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect), - surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage); + TRACE("created %p for %p %s color_bits %p-%p\n", surface, window, wine_dbgstr_rect(rect), + surface->header.color_bits, (char *)surface->header.color_bits + surface->info.bmiHeader.biSizeImage);
return &surface->header;
@@ -229,12 +228,12 @@ CGImageRef macdrv_get_surface_display_image(struct window_surface *window_surfac
if (copy_data) { - CFDataRef data = CFDataCreate(NULL, (UInt8*)surface->bits + offset, size); + CFDataRef data = CFDataCreate(NULL, (UInt8 *)window_surface->color_bits + offset, size); provider = CGDataProviderCreateWithCFData(data); CFRelease(data); } else - provider = CGDataProviderCreateWithData(NULL, surface->bits + offset, size, NULL); + provider = CGDataProviderCreateWithData(NULL, (UInt8 *)window_surface->color_bits + offset, size, NULL);
alphaInfo = surface->use_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; cgimage = CGImageCreate(CGRectGetWidth(visrect), CGRectGetHeight(visrect), diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index 752a560ddec..3447e151329 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -45,7 +45,6 @@ struct wayland_window_surface struct window_surface header; struct wayland_surface *wayland_surface; struct wayland_buffer_queue *wayland_buffer_queue; - void *bits; BITMAPINFO info; };
@@ -220,7 +219,7 @@ static void *wayland_window_surface_get_bitmap_info(struct window_surface *windo /* We don't store any additional information at the end of our BITMAPINFO, so * just copy the structure itself. */ memcpy(info, &surface->info, sizeof(*info)); - return surface->bits; + return window_surface->color_bits; }
/*********************************************************************** @@ -308,17 +307,15 @@ static void copy_pixel_region(char *src_pixels, RECT *src_rect, }
/********************************************************************** - * wayland_window_surface_copy_to_buffer + * wayland_shm_buffer_copy_data */ -static void wayland_window_surface_copy_to_buffer(struct wayland_window_surface *wws, - struct wayland_shm_buffer *buffer, - HRGN region) +static void wayland_shm_buffer_copy_data(struct wayland_shm_buffer *buffer, + char *bits, RECT *rect, + HRGN region) { - RECT wws_rect = {0, 0, wws->info.bmiHeader.biWidth, - abs(wws->info.bmiHeader.biHeight)}; RECT buffer_rect = {0, 0, buffer->width, buffer->height}; - TRACE("wws=%p buffer=%p\n", wws, buffer); - copy_pixel_region(wws->bits, &wws_rect, buffer->map_data, &buffer_rect, region); + TRACE("buffer=%p bits=%p rect=%s\n", buffer, bits, wine_dbgstr_rect(rect)); + copy_pixel_region(bits, rect, buffer->map_data, &buffer_rect, region); }
static void wayland_shm_buffer_copy(struct wayland_shm_buffer *src, @@ -396,7 +393,8 @@ static BOOL wayland_window_surface_flush(struct window_surface *window_surface, copy_from_window_region = shm_buffer->damage_region; }
- wayland_window_surface_copy_to_buffer(wws, shm_buffer, copy_from_window_region); + wayland_shm_buffer_copy_data(shm_buffer, window_surface->color_bits, + &window_surface->rect, copy_from_window_region);
pthread_mutex_lock(&wws->wayland_surface->mutex); if (wayland_surface_reconfigure(wws->wayland_surface)) @@ -437,7 +435,7 @@ static void wayland_window_surface_destroy(struct window_surface *window_surface
if (wws->wayland_buffer_queue) wayland_buffer_queue_destroy(wws->wayland_buffer_queue); - free(wws->bits); + free(window_surface->color_bits); free(wws); }
@@ -473,11 +471,11 @@ struct window_surface *wayland_window_surface_create(HWND hwnd, const RECT *rect wws->info.bmiHeader.biPlanes = 1; wws->info.bmiHeader.biSizeImage = width * height * 4;
- if (!(wws->bits = malloc(wws->info.bmiHeader.biSizeImage))) + if (!(wws->header.color_bits = malloc(wws->info.bmiHeader.biSizeImage))) goto failed;
- TRACE("created %p hwnd %p %s bits [%p,%p)\n", wws, hwnd, wine_dbgstr_rect(rect), - wws->bits, (char *)wws->bits + wws->info.bmiHeader.biSizeImage); + TRACE("created %p hwnd %p %s color_bits [%p,%p)\n", wws, hwnd, wine_dbgstr_rect(rect), + wws->header.color_bits, (char *)wws->header.color_bits + wws->info.bmiHeader.biSizeImage);
return &wws->header;
diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index df8fc8f1257..db175938c89 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1581,7 +1581,6 @@ struct x11drv_window_surface BOOL is_argb; DWORD alpha_bits; COLORREF color_key; - void *bits; #ifdef HAVE_LIBXXSHM XShmSegmentInfo shminfo; #endif @@ -1627,7 +1626,7 @@ static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len ) /*********************************************************************** * update_surface_region */ -static void update_surface_region( struct x11drv_window_surface *surface ) +static void update_surface_region( struct x11drv_window_surface *surface, const void *color_bits ) { #ifdef HAVE_LIBXSHAPE char buffer[4096]; @@ -1657,7 +1656,7 @@ static void update_surface_region( struct x11drv_window_surface *surface ) { case 16: { - WORD *bits = surface->bits; + const WORD *bits = color_bits; int stride = (width + 1) & ~1; UINT mask = masks[0] | masks[1] | masks[2];
@@ -1676,7 +1675,7 @@ static void update_surface_region( struct x11drv_window_surface *surface ) } case 24: { - BYTE *bits = surface->bits; + const BYTE *bits = color_bits; int stride = (width * 3 + 3) & ~3;
for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride) @@ -1702,7 +1701,7 @@ static void update_surface_region( struct x11drv_window_surface *surface ) } case 32: { - DWORD *bits = surface->bits; + const DWORD *bits = color_bits;
if (info->bmiHeader.biCompression == BI_RGB) { @@ -1833,7 +1832,7 @@ static void *x11drv_surface_get_bitmap_info( struct window_surface *window_surfa struct x11drv_window_surface *surface = get_x11_surface( window_surface );
memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS )); - return surface->bits; + return window_surface->color_bits; }
static XRectangle *xrectangles_from_rects( const RECT *rects, UINT count ) @@ -1879,10 +1878,10 @@ static void x11drv_surface_set_clip( struct window_surface *window_surface, cons static BOOL x11drv_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty ) { struct x11drv_window_surface *surface = get_x11_surface( window_surface ); - unsigned char *src = surface->bits; + unsigned char *src = window_surface->color_bits; unsigned char *dst = (unsigned char *)surface->image->data;
- if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface ); + if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface, window_surface->color_bits );
if (src != dst) { @@ -1926,11 +1925,11 @@ static void x11drv_surface_destroy( struct window_surface *window_surface ) { struct x11drv_window_surface *surface = get_x11_surface( window_surface );
- TRACE( "freeing %p bits %p\n", surface, surface->bits ); + TRACE( "freeing %p bits %p\n", surface, window_surface->color_bits ); if (surface->gc) XFreeGC( gdi_display, surface->gc ); if (surface->image) { - if (surface->image->data != surface->bits) free( surface->bits ); + if (surface->image->data != window_surface->color_bits) free( window_surface->color_bits ); #ifdef HAVE_LIBXXSHM if (surface->shminfo.shmid != -1) { @@ -2004,13 +2003,13 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn 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->bits = calloc( 1, surface->info.bmiHeader.biSizeImage ))) + if (!(surface->header.color_bits = calloc( 1, surface->info.bmiHeader.biSizeImage ))) goto failed; } - else surface->bits = surface->image->data; + else surface->header.color_bits = surface->image->data;
- TRACE( "created %p for %lx %s bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect), - surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage, + TRACE( "created %p for %lx %s color_bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect), + surface->header.color_bits, (char *)surface->header.color_bits + surface->info.bmiHeader.biSizeImage, surface->image->data );
return &surface->header; @@ -2033,7 +2032,7 @@ void set_surface_color_key( struct window_surface *window_surface, COLORREF colo window_surface_lock( window_surface ); prev = surface->color_key; set_color_key( surface, color_key ); - if (surface->color_key != prev) update_surface_region( surface ); + if (surface->color_key != prev) update_surface_region( surface, window_surface->color_bits ); window_surface_unlock( window_surface ); }
diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 588930f9e01..07d29c9b399 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -225,10 +225,11 @@ struct window_surface HWND hwnd; /* window the surface was created for */ RECT rect; /* constant, no locking needed */
- pthread_mutex_t mutex; - RECT bounds; /* dirty area rect, requires locking */ + pthread_mutex_t mutex; /* mutex needed for any field below */ + RECT bounds; /* dirty area rectangle */ HRGN clip_region; /* visible region of the surface, fully visible if 0 */ DWORD draw_start_ticks; /* start ticks of fresh draw */ + void *color_bits; /* pixel bits of the surface color */ /* driver-specific fields here */ };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 39 +++++++++++++++++++-------- dlls/wineandroid.drv/window.c | 21 ++++++++------- dlls/winemac.drv/surface.c | 34 +++++++++++------------ dlls/winewayland.drv/window_surface.c | 22 ++++++++------- dlls/winex11.drv/bitblt.c | 29 +++++++++++--------- include/wine/gdi_driver.h | 3 ++- 6 files changed, 85 insertions(+), 63 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 6bb090cedcf..f1a202f2e8b 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -156,6 +156,8 @@ static const struct window_surface_funcs offscreen_window_surface_funcs =
void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struct window_surface **surface ) { + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; struct offscreen_window_surface *impl; SIZE_T size; RECT surface_rect = *visible_rect; @@ -175,20 +177,22 @@ void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struc } else if (*surface) window_surface_release( *surface );
+ info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = surface_rect.right; + info->bmiHeader.biHeight = -surface_rect.bottom; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biSizeImage = surface_rect.right * surface_rect.right * 4; + info->bmiHeader.biCompression = BI_RGB; + /* create a new window surface */ *surface = NULL; - size = surface_rect.right * surface_rect.bottom * 4; + size = info->bmiHeader.biSizeImage; if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return; - window_surface_init( &impl->header, &offscreen_window_surface_funcs, hwnd, &surface_rect ); + window_surface_init( &impl->header, &offscreen_window_surface_funcs, hwnd, info, 0 );
impl->header.color_bits = (char *)&impl->info.bmiColors[0]; - impl->info.bmiHeader.biSize = sizeof( impl->info ); - impl->info.bmiHeader.biWidth = surface_rect.right; - impl->info.bmiHeader.biHeight = surface_rect.bottom; - impl->info.bmiHeader.biPlanes = 1; - impl->info.bmiHeader.biBitCount = 32; - impl->info.bmiHeader.biCompression = BI_RGB; - impl->info.bmiHeader.biSizeImage = size; + impl->info = *info;
TRACE( "created window surface %p\n", &impl->header );
@@ -197,14 +201,27 @@ void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struc
/* window surface common helpers */
-W32KAPI void window_surface_init( struct window_surface *surface, const struct window_surface_funcs *funcs, HWND hwnd, const RECT *rect ) +W32KAPI BOOL window_surface_init( struct window_surface *surface, const struct window_surface_funcs *funcs, + HWND hwnd, BITMAPINFO *info, HBITMAP bitmap ) { + struct bitblt_coords coords = {0}; + struct gdi_image_bits bits; + BITMAPOBJ *bmp; + surface->funcs = funcs; surface->ref = 1; surface->hwnd = hwnd; - surface->rect = *rect; + SetRect( &surface->rect, 0, 0, info->bmiHeader.biWidth, abs( info->bmiHeader.biHeight ) ); pthread_mutex_init( &surface->mutex, NULL ); reset_bounds( &surface->bounds ); + + if (!bitmap) return TRUE; + if (!(bmp = GDI_GetObjPtr( bitmap, NTGDI_OBJ_BITMAP ))) return FALSE; + get_image_from_bitmap( bmp, info, &bits, &coords ); + surface->color_bits = bits.ptr; + GDI_ReleaseObj( bitmap ); + + return TRUE; }
W32KAPI void window_surface_add_ref( struct window_surface *surface ) diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 657a5ff62cc..9b3ff2b456c 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -781,26 +781,29 @@ static struct window_surface *create_surface( HWND hwnd, const RECT *rect, { struct android_window_surface *surface; int width = rect->right - rect->left, height = rect->bottom - rect->top; + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + + set_color_info( info, src_alpha ); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = -height; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biSizeImage = get_dib_image_size( info );
surface = calloc( 1, FIELD_OFFSET( struct android_window_surface, info.bmiColors[3] )); if (!surface) return NULL; - window_surface_init( &surface->header, &android_surface_funcs, hwnd, rect ); - - set_color_info( &surface->info, src_alpha ); - surface->info.bmiHeader.biWidth = width; - surface->info.bmiHeader.biHeight = -height; /* top-down */ - surface->info.bmiHeader.biPlanes = 1; - surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info ); + if (!window_surface_init( &surface->header, &android_surface_funcs, hwnd, info, 0 )) goto failed; + memcpy( &surface->info, info, get_dib_info_size( info, DIB_RGB_COLORS ) );
surface->window = get_ioctl_window( hwnd ); surface->alpha = alpha; set_color_key( surface, color_key );
- if (!(surface->header.color_bits = malloc( surface->info.bmiHeader.biSizeImage ))) + if (!(surface->header.color_bits = malloc( info->bmiHeader.biSizeImage ))) goto failed;
TRACE( "created %p hwnd %p %s color_bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect), - surface->header.color_bits, (char *)surface->header.color_bits + surface->info.bmiHeader.biSizeImage ); + surface->header.color_bits, (char *)surface->header.color_bits + info->bmiHeader.biSizeImage );
return &surface->header;
diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index a34df22397a..7d3f8a69be2 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -133,37 +133,33 @@ struct window_surface *create_surface(HWND hwnd, macdrv_window window, const REC { struct macdrv_window_surface *surface; int width = rect->right - rect->left, height = rect->bottom - rect->top; - DWORD *colors; DWORD window_background; + char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = -height; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biSizeImage = get_dib_image_size(info); + info->bmiHeader.biCompression = BI_RGB;
surface = calloc(1, FIELD_OFFSET(struct macdrv_window_surface, info.bmiColors[3])); if (!surface) return NULL; - window_surface_init(&surface->header, &macdrv_surface_funcs, hwnd, rect); - - surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader); - surface->info.bmiHeader.biWidth = width; - surface->info.bmiHeader.biHeight = -height; /* top-down */ - surface->info.bmiHeader.biPlanes = 1; - surface->info.bmiHeader.biBitCount = 32; - surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info); - surface->info.bmiHeader.biCompression = BI_RGB; - surface->info.bmiHeader.biClrUsed = 0; - - colors = (DWORD *)((char *)&surface->info + surface->info.bmiHeader.biSize); - colors[0] = 0x00ff0000; - colors[1] = 0x0000ff00; - colors[2] = 0x000000ff; + if (!window_surface_init(&surface->header, &macdrv_surface_funcs, hwnd, info, 0)) goto failed; + memcpy(&surface->info, info, offsetof(BITMAPINFO, bmiColors[3]));
surface->window = window; if (old_surface) surface->header.bounds = old_surface->bounds; surface->use_alpha = use_alpha; - surface->header.color_bits = malloc(surface->info.bmiHeader.biSizeImage); + surface->header.color_bits = malloc(info->bmiHeader.biSizeImage); if (!surface->header.color_bits) goto failed; window_background = macdrv_window_background_color(); - memset_pattern4(surface->header.color_bits, &window_background, surface->info.bmiHeader.biSizeImage); + memset_pattern4(surface->header.color_bits, &window_background, info->bmiHeader.biSizeImage);
TRACE("created %p for %p %s color_bits %p-%p\n", surface, window, wine_dbgstr_rect(rect), - surface->header.color_bits, (char *)surface->header.color_bits + surface->info.bmiHeader.biSizeImage); + surface->header.color_bits, (char *)surface->header.color_bits + info->bmiHeader.biSizeImage);
return &surface->header;
diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index 3447e151329..34523d8c54a 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -452,24 +452,26 @@ static const struct window_surface_funcs wayland_window_surface_funcs = */ struct window_surface *wayland_window_surface_create(HWND hwnd, const RECT *rect) { + char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; + BITMAPINFO *info = (BITMAPINFO *)buffer; struct wayland_window_surface *wws; int width = rect->right - rect->left; int height = rect->bottom - rect->top;
TRACE("hwnd %p rect %s\n", hwnd, wine_dbgstr_rect(rect));
+ info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = -height; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biSizeImage = width * height * 4; + info->bmiHeader.biCompression = BI_RGB; + wws = calloc(1, sizeof(*wws)); if (!wws) return NULL; - window_surface_init(&wws->header, &wayland_window_surface_funcs, hwnd, rect); - - wws->info.bmiHeader.biSize = sizeof(wws->info.bmiHeader); - wws->info.bmiHeader.biClrUsed = 0; - wws->info.bmiHeader.biBitCount = 32; - wws->info.bmiHeader.biCompression = BI_RGB; - wws->info.bmiHeader.biWidth = width; - wws->info.bmiHeader.biHeight = -height; /* top-down */ - wws->info.bmiHeader.biPlanes = 1; - wws->info.bmiHeader.biSizeImage = width * height * 4; + if (!window_surface_init(&wws->header, &wayland_window_surface_funcs, hwnd, info, 0)) goto failed; + wws->info = *info;
if (!(wws->header.color_bits = malloc(wws->info.bmiHeader.biSizeImage))) goto failed; diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index db175938c89..dda5262c6f8 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1961,24 +1961,27 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn COLORREF color_key, BOOL use_alpha ) { const XPixmapFormatValues *format = pixmap_formats[vis->depth]; + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; struct x11drv_window_surface *surface; int width = rect->right - rect->left, height = rect->bottom - rect->top; int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3;
+ info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = -height; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = format->bits_per_pixel; + info->bmiHeader.biSizeImage = get_dib_image_size( info ); + if (format->bits_per_pixel > 8) set_color_info( vis, info, use_alpha ); + surface = calloc( 1, FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] )); if (!surface) return NULL; - window_surface_init( &surface->header, &x11drv_surface_funcs, hwnd, rect ); - - surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader); - surface->info.bmiHeader.biWidth = width; - surface->info.bmiHeader.biHeight = -height; /* top-down */ - surface->info.bmiHeader.biPlanes = 1; - surface->info.bmiHeader.biBitCount = format->bits_per_pixel; - surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info ); - if (format->bits_per_pixel > 8) set_color_info( vis, &surface->info, use_alpha ); + if (!window_surface_init( &surface->header, &x11drv_surface_funcs, hwnd, info, 0 )) goto failed; + memcpy( &surface->info, info, get_dib_info_size( info, DIB_RGB_COLORS ) );
surface->window = window; - surface->is_argb = (use_alpha && vis->depth == 32 && surface->info.bmiHeader.biCompression == BI_RGB); + surface->is_argb = (use_alpha && vis->depth == 32 && info->bmiHeader.biCompression == BI_RGB); set_color_key( surface, color_key );
#ifdef HAVE_LIBXXSHM @@ -1989,7 +1992,7 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn surface->image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL, width, height, 32, 0 ); if (!surface->image) goto failed; - surface->image->data = malloc( surface->info.bmiHeader.biSizeImage ); + surface->image->data = malloc( info->bmiHeader.biSizeImage ); if (!surface->image->data) goto failed; }
@@ -2003,13 +2006,13 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn 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, surface->info.bmiHeader.biSizeImage ))) + if (!(surface->header.color_bits = calloc( 1, info->bmiHeader.biSizeImage ))) goto failed; } else surface->header.color_bits = surface->image->data;
TRACE( "created %p for %lx %s color_bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect), - surface->header.color_bits, (char *)surface->header.color_bits + surface->info.bmiHeader.biSizeImage, + surface->header.color_bits, (char *)surface->header.color_bits + info->bmiHeader.biSizeImage, surface->image->data );
return &surface->header; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 07d29c9b399..556e33d1fa2 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -233,7 +233,8 @@ struct window_surface /* driver-specific fields here */ };
-W32KAPI void window_surface_init( struct window_surface *surface, const struct window_surface_funcs *funcs, HWND hwnd, const RECT *rect ); +W32KAPI BOOL window_surface_init( struct window_surface *surface, const struct window_surface_funcs *funcs, + HWND hwnd, BITMAPINFO *info, HBITMAP bitmap ); W32KAPI void window_surface_add_ref( struct window_surface *surface ); W32KAPI void window_surface_release( struct window_surface *surface ); W32KAPI void window_surface_lock( struct window_surface *surface );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/bitblt.c | 115 +++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 44 deletions(-)
diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index dda5262c6f8..7390f294d19 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1570,20 +1570,25 @@ DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo return ret; }
+struct x11drv_image +{ + XImage *ximage; /* XImage used for X11 drawing */ + void *data; /* pixels allocated for XImage */ +#ifdef HAVE_LIBXXSHM + XShmSegmentInfo shminfo; +#endif +};
struct x11drv_window_surface { struct window_surface header; Window window; GC gc; - XImage *image; + struct x11drv_image *image; BOOL byteswap; BOOL is_argb; DWORD alpha_bits; COLORREF color_key; -#ifdef HAVE_LIBXXSHM - XShmSegmentInfo shminfo; -#endif BITMAPINFO info; /* variable size, must be last */ };
@@ -1824,6 +1829,45 @@ failed: } #endif /* HAVE_LIBXXSHM */
+static void x11drv_image_destroy( struct x11drv_image *image ) +{ +#ifdef HAVE_LIBXXSHM + if (image->shminfo.shmid != -1) + { + XShmDetach( gdi_display, &image->shminfo ); + shmdt( image->shminfo.shmaddr ); + } +#endif + + image->ximage->data = NULL; /* avoid XDestroyImage freeing the data */ + XDestroyImage( image->ximage ); + image->ximage = NULL; + + free( image->data ); +} + +static struct x11drv_image *x11drv_image_create( const BITMAPINFO *info, const XVisualInfo *vis ) +{ + struct x11drv_image *image; + + if (!(image = calloc( 1, sizeof(*image) ))) return NULL; +#ifdef HAVE_LIBXXSHM + image->ximage = create_shm_image( vis, info->bmiHeader.biWidth, abs( info->bmiHeader.biHeight ), &image->shminfo ); +#endif + if (!image->ximage) image->ximage = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL, + info->bmiHeader.biWidth, abs( info->bmiHeader.biHeight ), 32, 0 ); + if (!image->ximage) goto failed; + + if (!image->ximage->data) image->ximage->data = image->data = malloc( info->bmiHeader.biSizeImage ); + if (!image->ximage->data) goto failed; + return image; + +failed: + if (image) XDestroyImage( image->ximage ); + free( image ); + return NULL; +} + /*********************************************************************** * x11drv_surface_get_bitmap_info */ @@ -1878,15 +1922,16 @@ static void x11drv_surface_set_clip( struct window_surface *window_surface, cons static BOOL x11drv_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty ) { struct x11drv_window_surface *surface = get_x11_surface( window_surface ); + XImage *ximage = surface->image->ximage; unsigned char *src = window_surface->color_bits; - unsigned char *dst = (unsigned char *)surface->image->data; + unsigned char *dst = (unsigned char *)ximage->data;
if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface, window_surface->color_bits );
if (src != dst) { - int map[256], *mapping = get_window_surface_mapping( surface->image->bits_per_pixel, map ); - int width_bytes = surface->image->bytes_per_line; + int map[256], *mapping = get_window_surface_mapping( ximage->bits_per_pixel, map ); + int width_bytes = ximage->bytes_per_line;
src += dirty->top * width_bytes; dst += dirty->top * width_bytes; @@ -1895,7 +1940,7 @@ static BOOL x11drv_surface_flush( struct window_surface *window_surface, const R } else if (surface->alpha_bits) { - int x, y, stride = surface->image->bytes_per_line / sizeof(ULONG); + int x, y, stride = ximage->bytes_per_line / sizeof(ULONG); ULONG *ptr = (ULONG *)dst + dirty->top * stride;
for (y = dirty->top; y < dirty->bottom; y++, ptr += stride) @@ -1904,13 +1949,13 @@ static BOOL x11drv_surface_flush( struct window_surface *window_surface, const R }
#ifdef HAVE_LIBXXSHM - if (surface->shminfo.shmid != -1) - XShmPutImage( gdi_display, surface->window, surface->gc, surface->image, dirty->left, + if (surface->image->shminfo.shmid != -1) + XShmPutImage( gdi_display, surface->window, surface->gc, ximage, dirty->left, dirty->top, rect->left + dirty->left, rect->top + dirty->top, dirty->right - dirty->left, dirty->bottom - dirty->top, False ); else #endif - XPutImage( gdi_display, surface->window, surface->gc, surface->image, dirty->left, + XPutImage( gdi_display, surface->window, surface->gc, ximage, dirty->left, dirty->top, rect->left + dirty->left, rect->top + dirty->top, dirty->right - dirty->left, dirty->bottom - dirty->top ); XFlush( gdi_display ); @@ -1927,22 +1972,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) - { - if (surface->image->data != window_surface->color_bits) free( window_surface->color_bits ); -#ifdef HAVE_LIBXXSHM - if (surface->shminfo.shmid != -1) - { - XShmDetach( gdi_display, &surface->shminfo ); - shmdt( surface->shminfo.shmaddr ); - } - else -#endif - free( surface->image->data ); - surface->image->data = NULL; - XDestroyImage( surface->image ); - } - + if (surface->image) x11drv_image_destroy( surface->image ); free( surface ); }
@@ -1966,6 +1996,8 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn struct x11drv_window_surface *surface; 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; + UINT size;
info->bmiHeader.biSize = sizeof(info->bmiHeader); info->bmiHeader.biWidth = width; @@ -1975,8 +2007,15 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn info->bmiHeader.biSizeImage = get_dib_image_size( info ); if (format->bits_per_pixel > 8) set_color_info( vis, info, use_alpha );
- surface = calloc( 1, FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] )); - if (!surface) return NULL; + size = FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ); + if (!(image = x11drv_image_create( info, vis ))) return NULL; + if (!(surface = calloc( 1, size ))) + { + x11drv_image_destroy( image ); + return NULL; + } + surface->image = image; + if (!window_surface_init( &surface->header, &x11drv_surface_funcs, hwnd, info, 0 )) goto failed; memcpy( &surface->info, info, get_dib_info_size( info, DIB_RGB_COLORS ) );
@@ -1984,21 +2023,9 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn surface->is_argb = (use_alpha && vis->depth == 32 && info->bmiHeader.biCompression == BI_RGB); set_color_key( surface, color_key );
-#ifdef HAVE_LIBXXSHM - surface->image = create_shm_image( vis, width, height, &surface->shminfo ); - if (!surface->image) -#endif - { - surface->image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL, - width, height, 32, 0 ); - if (!surface->image) goto failed; - surface->image->data = malloc( info->bmiHeader.biSizeImage ); - if (!surface->image->data) goto failed; - } - surface->gc = XCreateGC( gdi_display, window, 0, NULL ); XSetSubwindowMode( gdi_display, surface->gc, IncludeInferiors ); - surface->byteswap = image_needs_byteswap( surface->image, is_r8g8b8(vis), format->bits_per_pixel ); + 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); @@ -2009,11 +2036,11 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn if (!(surface->header.color_bits = calloc( 1, info->bmiHeader.biSizeImage ))) goto failed; } - else surface->header.color_bits = surface->image->data; + 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), surface->header.color_bits, (char *)surface->header.color_bits + info->bmiHeader.biSizeImage, - surface->image->data ); + surface->image->ximage->data );
return &surface->header;
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 );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 11 ++++------- dlls/wineandroid.drv/window.c | 8 ++------ dlls/winemac.drv/surface.c | 6 ++---- dlls/winewayland.drv/window_surface.c | 6 +----- dlls/winex11.drv/bitblt.c | 10 +--------- include/wine/gdi_driver.h | 3 ++- 6 files changed, 12 insertions(+), 32 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index f1a202f2e8b..5a8bfa0d854 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -159,7 +159,6 @@ void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struc char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; BITMAPINFO *info = (BITMAPINFO *)buffer; struct offscreen_window_surface *impl; - SIZE_T size; RECT surface_rect = *visible_rect;
TRACE( "hwnd %p, visible_rect %s, surface %p.\n", hwnd, wine_dbgstr_rect( visible_rect ), surface ); @@ -187,11 +186,8 @@ void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struc
/* create a new window surface */ *surface = NULL; - size = info->bmiHeader.biSizeImage; - if (!(impl = calloc(1, offsetof( struct offscreen_window_surface, info.bmiColors[0] ) + size))) return; + if (!(impl = calloc(1, sizeof(*impl)))) return; window_surface_init( &impl->header, &offscreen_window_surface_funcs, hwnd, info, 0 ); - - impl->header.color_bits = (char *)&impl->info.bmiColors[0]; impl->info = *info;
TRACE( "created window surface %p\n", &impl->header ); @@ -215,8 +211,8 @@ W32KAPI BOOL window_surface_init( struct window_surface *surface, const struct w pthread_mutex_init( &surface->mutex, NULL ); reset_bounds( &surface->bounds );
- if (!bitmap) return TRUE; - if (!(bmp = GDI_GetObjPtr( bitmap, NTGDI_OBJ_BITMAP ))) return FALSE; + if (!bitmap) bitmap = NtGdiCreateDIBSection( 0, NULL, 0, info, DIB_RGB_COLORS, 0, 0, 0, NULL ); + if (!(surface->color_bitmap = bitmap) || !(bmp = GDI_GetObjPtr( bitmap, NTGDI_OBJ_BITMAP ))) return FALSE; get_image_from_bitmap( bmp, info, &bits, &coords ); surface->color_bits = bits.ptr; GDI_ReleaseObj( bitmap ); @@ -236,6 +232,7 @@ W32KAPI void window_surface_release( struct window_surface *surface ) { if (surface != &dummy_surface) pthread_mutex_destroy( &surface->mutex ); if (surface->clip_region) NtGdiDeleteObjectApp( surface->clip_region ); + if (surface->color_bitmap) NtGdiDeleteObjectApp( surface->color_bitmap ); surface->funcs->destroy( surface ); } } diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 9b3ff2b456c..b52fe4dc33e 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -732,11 +732,10 @@ static void android_surface_destroy( struct window_surface *window_surface ) { struct android_window_surface *surface = get_android_surface( window_surface );
- TRACE( "freeing %p bits %p\n", surface, window_surface->color_bits ); + TRACE( "freeing %p\n", surface );
free( surface->clip_rects ); release_ioctl_window( surface->window ); - free( window_surface->color_bits ); free( surface ); }
@@ -799,10 +798,7 @@ static struct window_surface *create_surface( HWND hwnd, const RECT *rect, surface->alpha = alpha; set_color_key( surface, color_key );
- if (!(surface->header.color_bits = malloc( info->bmiHeader.biSizeImage ))) - goto failed; - - TRACE( "created %p hwnd %p %s color_bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect), + TRACE( "created %p hwnd %p %s bits %p-%p\n", surface, hwnd, wine_dbgstr_rect(rect), surface->header.color_bits, (char *)surface->header.color_bits + info->bmiHeader.biSizeImage );
return &surface->header; diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index 7d3f8a69be2..58f1dc39bc2 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -106,8 +106,7 @@ static void macdrv_surface_destroy(struct window_surface *window_surface) { struct macdrv_window_surface *surface = get_mac_surface(window_surface);
- TRACE("freeing %p bits %p\n", surface, window_surface->color_bits); - free(window_surface->color_bits); + TRACE("freeing %p\n", surface); free(surface); }
@@ -153,8 +152,7 @@ struct window_surface *create_surface(HWND hwnd, macdrv_window window, const REC surface->window = window; if (old_surface) surface->header.bounds = old_surface->bounds; surface->use_alpha = use_alpha; - surface->header.color_bits = malloc(info->bmiHeader.biSizeImage); - if (!surface->header.color_bits) goto failed; + window_background = macdrv_window_background_color(); memset_pattern4(surface->header.color_bits, &window_background, info->bmiHeader.biSizeImage);
diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index 34523d8c54a..78d04f46413 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -435,7 +435,6 @@ static void wayland_window_surface_destroy(struct window_surface *window_surface
if (wws->wayland_buffer_queue) wayland_buffer_queue_destroy(wws->wayland_buffer_queue); - free(window_surface->color_bits); free(wws); }
@@ -473,10 +472,7 @@ struct window_surface *wayland_window_surface_create(HWND hwnd, const RECT *rect if (!window_surface_init(&wws->header, &wayland_window_surface_funcs, hwnd, info, 0)) goto failed; wws->info = *info;
- if (!(wws->header.color_bits = malloc(wws->info.bmiHeader.biSizeImage))) - goto failed; - - TRACE("created %p hwnd %p %s color_bits [%p,%p)\n", wws, hwnd, wine_dbgstr_rect(rect), + TRACE("created %p hwnd %p %s bits [%p,%p)\n", wws, hwnd, wine_dbgstr_rect(rect), wws->header.color_bits, (char *)wws->header.color_bits + wws->info.bmiHeader.biSizeImage);
return &wws->header; diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 8e928bd491c..0de5eaf1e51 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1586,7 +1586,6 @@ struct x11drv_window_surface Window window; GC gc; struct x11drv_image *image; - HBITMAP bitmap; /* bitmap exposed to win32u */ BOOL is_argb; DWORD alpha_bits; COLORREF color_key; @@ -1914,15 +1913,10 @@ static struct x11drv_image *x11drv_image_create( const BITMAPINFO *info, const X /* 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; } @@ -2029,10 +2023,9 @@ static void x11drv_surface_destroy( struct window_surface *window_surface ) { struct x11drv_window_surface *surface = get_x11_surface( window_surface );
- TRACE( "freeing %p bits %p\n", surface, window_surface->color_bits ); + TRACE( "freeing %p\n", surface ); if (surface->gc) XFreeGC( gdi_display, surface->gc ); if (surface->image) x11drv_image_destroy( surface->image ); - if (surface->bitmap) NtGdiDeleteObjectApp( surface->bitmap ); free( surface ); }
@@ -2077,7 +2070,6 @@ struct window_surface *create_surface( HWND hwnd, Window window, const XVisualIn return NULL; } surface->image = image; - surface->bitmap = bitmap;
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 ) ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 556e33d1fa2..ce954a7f4d8 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -229,7 +229,8 @@ struct window_surface RECT bounds; /* dirty area rectangle */ HRGN clip_region; /* visible region of the surface, fully visible if 0 */ DWORD draw_start_ticks; /* start ticks of fresh draw */ - void *color_bits; /* pixel bits of the surface color */ + HBITMAP color_bitmap; /* bitmap for the surface colors */ + void *color_bits; /* pixel bits of the color bitmap */ /* driver-specific fields here */ };
v2: Remove winemac color masks which aren't necessary.
Emil Velikov (@xexaxo) commented about dlls/win32u/dce.c:
void create_offscreen_window_surface( HWND hwnd, const RECT *visible_rect, struct window_surface **surface ) {
- char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
Does we need the 256 here?
Note that *Clr* and *PelsPer* bits in the header are not initialised, so we pick random values off the stack.
Emil Velikov (@xexaxo) commented about dlls/wineandroid.drv/window.c:
{ struct android_window_surface *surface; int width = rect->right - rect->left, height = rect->bottom - rect->top;
- char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
Same comments apply here. Although set_color_info particularly solves that... Although it sets the Colour(s) where there MacOS ones got removed - why is that btw?
On Mon Jun 3 12:46:52 2024 +0000, Emil Velikov wrote:
Does we need the 256 here? Note that *Clr* and *PelsPer* bits in the header are not initialised, so we pick random values off the stack.
The buffer isn't really needed but I think it makes the code more consistent, and easier to change again later [^1]. The win32u side can also safely assume it is called with enough room for any kind of bitmap info.
Note that _Clr_ and _PelsPer_ bits in the header are not initialised, so we pick random values off the stack.
Right, I'll fix the uninitialized data, thanks. I think it should not matter with BI_RGB compression, but maybe it does.
[^1]: Several drivers only use 32bit bitmap, and that could be moved out of the drivers at some point. Even for winex11 I'm not completely sure it's worth keeping the non-32bit support, but I'm trying to keep the behavior the same for now.
On Mon Jun 3 12:49:13 2024 +0000, Emil Velikov wrote:
Same comments apply here. Although set_color_info particularly solves that... Although it sets the Colour(s) where there MacOS ones got removed - why is that btw?
The macOS driver always use `biCompression = BI_RGB`, which means that the `bmiColors` field isn't used. When `biCompression = BI_BITFIELD`, the first three `bmiColors` elements provide bit masks for the R/G/B colors in the bitmap (so you can re-order them for instance).
Another semantic difference, and that's what `wineandroid` is doing, is that `biBitCount = 32` + `biCompression = BI_RGB` implies that the alpha channel is valid in the most significant bits. Otoh `biBitCount = 32` + `biCompression = BI_BITFIELDS` implies that the alpha channel should be ignored (or that there is none, for instance with a `R11B10G11` format which could be described through the `bmiColors` field, though that's only theoretical).
For the purpose of window surfaces, having an alpha channel or not has some implications on whether the surface can be used for layered windows or not. Ultimately I think we could perhaps use 32-bit surfaces with alpha channel all the time, but right now each drivers manages that a bit differently.
Emil Velikov (@xexaxo) commented about dlls/winex11.drv/bitblt.c:
return ret;
}
+struct x11drv_image +{
- XImage *ximage; /* XImage used for X11 drawing */
- void *data; /* pixels allocated for XImage */
If it were me, I would make this a bool to indicate if we allocated it or not. Then reduce the pointer setting/scrubbing
On Mon Jun 3 13:07:01 2024 +0000, Rémi Bernon wrote:
The macOS driver always use `biCompression = BI_RGB`, which means that the `bmiColors` field isn't used. When `biCompression = BI_BITFIELD`, the first three `bmiColors` elements provide bit masks for the R/G/B colors in the bitmap (so you can re-order them for instance). Another semantic difference, and that's what `wineandroid` is doing, is that `biBitCount = 32` + `biCompression = BI_RGB` implies that the alpha channel is valid in the most significant bits. Otoh `biBitCount = 32` + `biCompression = BI_BITFIELDS` implies that the alpha channel should be ignored (or that there is none, for instance with a `R11B10G11` format which could be described through the `bmiColors` field, though that's only theoretical). For the purpose of window surfaces, having an alpha channel or not has some implications on whether the surface can be used for layered windows or not. Ultimately I think we could perhaps use 32-bit surfaces with alpha channel all the time, but right now each drivers manages that a bit differently.
Thank you for the extensive information.
Consistently using 32bit surfaces with alpha makes sense, although it's best to have those done incrementally ... IIRC we had some perf regressions in Mesa/i965 with similar a change.
HTH o/
On Mon Jun 3 13:07:16 2024 +0000, Emil Velikov wrote:
If it were me, I would make this a bool to indicate if we allocated it or not. Then reduce the pointer setting/scrubbing
Yeah it's a bit messy, though I hope it could be simplified in the future. I'll try to make it a bit better.
Ultimately I would like to create NT sections first, and then allocate the HBITMAP, and XSHM image from it when possible, but it looks like the only way to do that is through the XCB API, for `xcb_shm_attach_fd`, as Xlib will only let us use the old `shmget`/`shmat` API.
This would be the first case where we would need XCB in Wine, and although I see plenty of reasons to move to XCB, I'm not sure how to do introduce it properly and whether it's worth it just for that.