mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-04 18:57:38 +00:00
winewayland.drv: Implement a simple window_surface flush.
Flush a window_surface to a Wayland surface by creating a wl_shm buffer matching the window size, copying the whole window contents to that buffer and attaching it to the corresponding Wayland surface.
This commit is contained in:
parent
d53cb7206d
commit
6b0a84c8d9
|
@ -94,6 +94,10 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
|
|||
version < 2 ? version : 2);
|
||||
xdg_wm_base_add_listener(process_wayland.xdg_wm_base, &xdg_wm_base_listener, NULL);
|
||||
}
|
||||
else if (strcmp(interface, "wl_shm") == 0)
|
||||
{
|
||||
process_wayland.wl_shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void registry_handle_global_remove(void *data, struct wl_registry *registry,
|
||||
|
@ -176,6 +180,11 @@ BOOL wayland_process_init(void)
|
|||
ERR("Wayland compositor doesn't support xdg_wm_base\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!process_wayland.wl_shm)
|
||||
{
|
||||
ERR("Wayland compositor doesn't support wl_shm\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wayland_init_display_devices(FALSE);
|
||||
|
||||
|
|
|
@ -25,12 +25,17 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "waylanddrv.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/server.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
|
||||
|
||||
/* We only use 4 byte formats. */
|
||||
#define WINEWAYLAND_BYTES_PER_PIXEL 4
|
||||
|
||||
/* Protects access to the user data of xdg_surface */
|
||||
static pthread_mutex_t xdg_data_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
@ -197,3 +202,130 @@ void wayland_surface_clear_role(struct wayland_surface *surface)
|
|||
|
||||
wl_display_flush(process_wayland.wl_display);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_surface_attach_shm
|
||||
*
|
||||
* Attaches a SHM buffer to a wayland surface.
|
||||
*/
|
||||
void wayland_surface_attach_shm(struct wayland_surface *surface,
|
||||
struct wayland_shm_buffer *shm_buffer)
|
||||
{
|
||||
TRACE("surface=%p shm_buffer=%p (%dx%d)\n",
|
||||
surface, shm_buffer, shm_buffer->width, shm_buffer->height);
|
||||
|
||||
wl_surface_attach(surface->wl_surface, shm_buffer->wl_buffer, 0, 0);
|
||||
wl_surface_damage_buffer(surface->wl_surface, 0, 0,
|
||||
shm_buffer->width, shm_buffer->height);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_shm_buffer_destroy
|
||||
*
|
||||
* Destroys a SHM buffer.
|
||||
*/
|
||||
void wayland_shm_buffer_destroy(struct wayland_shm_buffer *shm_buffer)
|
||||
{
|
||||
TRACE("%p map=%p\n", shm_buffer, shm_buffer->map_data);
|
||||
|
||||
if (shm_buffer->wl_buffer)
|
||||
wl_buffer_destroy(shm_buffer->wl_buffer);
|
||||
if (shm_buffer->map_data)
|
||||
NtUnmapViewOfSection(GetCurrentProcess(), shm_buffer->map_data);
|
||||
|
||||
free(shm_buffer);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_shm_buffer_create
|
||||
*
|
||||
* Creates a SHM buffer with the specified width, height and format.
|
||||
*/
|
||||
struct wayland_shm_buffer *wayland_shm_buffer_create(int width, int height,
|
||||
enum wl_shm_format format)
|
||||
{
|
||||
struct wayland_shm_buffer *shm_buffer = NULL;
|
||||
HANDLE handle = 0;
|
||||
int fd = -1;
|
||||
SIZE_T view_size = 0;
|
||||
LARGE_INTEGER section_size;
|
||||
NTSTATUS status;
|
||||
struct wl_shm_pool *pool;
|
||||
int stride, size;
|
||||
|
||||
stride = width * WINEWAYLAND_BYTES_PER_PIXEL;
|
||||
size = stride * height;
|
||||
if (size == 0)
|
||||
{
|
||||
ERR("Invalid shm_buffer size %dx%d\n", width, height);
|
||||
goto err;
|
||||
}
|
||||
|
||||
shm_buffer = calloc(1, sizeof(*shm_buffer));
|
||||
if (!shm_buffer)
|
||||
{
|
||||
ERR("Failed to allocate space for SHM buffer\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
TRACE("%p %dx%d format=%d size=%d\n", shm_buffer, width, height, format, size);
|
||||
|
||||
shm_buffer->width = width;
|
||||
shm_buffer->height = height;
|
||||
shm_buffer->map_size = size;
|
||||
|
||||
section_size.QuadPart = size;
|
||||
status = NtCreateSection(&handle,
|
||||
GENERIC_READ | SECTION_MAP_READ | SECTION_MAP_WRITE,
|
||||
NULL, §ion_size, PAGE_READWRITE, SEC_COMMIT, 0);
|
||||
if (status)
|
||||
{
|
||||
ERR("Failed to create SHM section status=0x%lx\n", (long)status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = NtMapViewOfSection(handle, GetCurrentProcess(),
|
||||
(PVOID)&shm_buffer->map_data, 0, 0, NULL,
|
||||
&view_size, ViewUnmap, 0, PAGE_READWRITE);
|
||||
if (status)
|
||||
{
|
||||
shm_buffer->map_data = NULL;
|
||||
ERR("Failed to create map SHM handle status=0x%lx\n", (long)status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = wine_server_handle_to_fd(handle, FILE_READ_DATA, &fd, NULL);
|
||||
if (status)
|
||||
{
|
||||
ERR("Failed to get fd from SHM handle status=0x%lx\n", (long)status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pool = wl_shm_create_pool(process_wayland.wl_shm, fd, size);
|
||||
if (!pool)
|
||||
{
|
||||
ERR("Failed to create SHM pool fd=%d size=%d\n", fd, size);
|
||||
goto err;
|
||||
}
|
||||
shm_buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0, width, height,
|
||||
stride, format);
|
||||
wl_shm_pool_destroy(pool);
|
||||
if (!shm_buffer->wl_buffer)
|
||||
{
|
||||
ERR("Failed to create SHM buffer %dx%d\n", width, height);
|
||||
goto err;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
NtClose(handle);
|
||||
|
||||
TRACE("=> map=%p\n", shm_buffer->map_data);
|
||||
|
||||
return shm_buffer;
|
||||
|
||||
err:
|
||||
if (fd >= 0) close(fd);
|
||||
if (handle) NtClose(handle);
|
||||
if (shm_buffer) wayland_shm_buffer_destroy(shm_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ struct wayland
|
|||
struct zxdg_output_manager_v1 *zxdg_output_manager_v1;
|
||||
struct wl_compositor *wl_compositor;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct wl_shm *wl_shm;
|
||||
struct wl_list output_list;
|
||||
/* Protects the output_list and the wayland_output.current states. */
|
||||
pthread_mutex_t output_mutex;
|
||||
|
@ -102,6 +103,14 @@ struct wayland_surface
|
|||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
struct wayland_shm_buffer
|
||||
{
|
||||
struct wl_buffer *wl_buffer;
|
||||
int width, height;
|
||||
void *map_data;
|
||||
size_t map_size;
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* Wayland initialization
|
||||
*/
|
||||
|
@ -125,12 +134,24 @@ struct wayland_surface *wayland_surface_create(void) DECLSPEC_HIDDEN;
|
|||
void wayland_surface_destroy(struct wayland_surface *surface) DECLSPEC_HIDDEN;
|
||||
void wayland_surface_make_toplevel(struct wayland_surface *surface) DECLSPEC_HIDDEN;
|
||||
void wayland_surface_clear_role(struct wayland_surface *surface) DECLSPEC_HIDDEN;
|
||||
void wayland_surface_attach_shm(struct wayland_surface *surface,
|
||||
struct wayland_shm_buffer *shm_buffer) DECLSPEC_HIDDEN;
|
||||
|
||||
/**********************************************************************
|
||||
* Wayland SHM buffer
|
||||
*/
|
||||
|
||||
struct wayland_shm_buffer *wayland_shm_buffer_create(int width, int height,
|
||||
enum wl_shm_format format) DECLSPEC_HIDDEN;
|
||||
void wayland_shm_buffer_destroy(struct wayland_shm_buffer *shm_buffer) DECLSPEC_HIDDEN;
|
||||
|
||||
/**********************************************************************
|
||||
* Wayland window surface
|
||||
*/
|
||||
|
||||
struct window_surface *wayland_window_surface_create(HWND hwnd, const RECT *rect) DECLSPEC_HIDDEN;
|
||||
void wayland_window_surface_update_wayland_surface(struct window_surface *surface,
|
||||
struct wayland_surface *wayland_surface) DECLSPEC_HIDDEN;
|
||||
|
||||
/**********************************************************************
|
||||
* USER driver functions
|
||||
|
|
|
@ -107,7 +107,11 @@ static void wayland_win_data_destroy(struct wayland_win_data *data)
|
|||
|
||||
pthread_mutex_unlock(&win_data_mutex);
|
||||
|
||||
if (data->window_surface) window_surface_release(data->window_surface);
|
||||
if (data->window_surface)
|
||||
{
|
||||
wayland_window_surface_update_wayland_surface(data->window_surface, NULL);
|
||||
window_surface_release(data->window_surface);
|
||||
}
|
||||
if (data->wayland_surface) wayland_surface_destroy(data->wayland_surface);
|
||||
free(data);
|
||||
}
|
||||
|
@ -153,6 +157,8 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
|
|||
/* We don't want wayland surfaces for child windows. */
|
||||
if (parent != NtUserGetDesktopWindow() && parent != 0)
|
||||
{
|
||||
if (data->window_surface)
|
||||
wayland_window_surface_update_wayland_surface(data->window_surface, NULL);
|
||||
if (surface) wayland_surface_destroy(surface);
|
||||
surface = NULL;
|
||||
goto out;
|
||||
|
@ -178,6 +184,9 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
|
|||
pthread_mutex_unlock(&surface->mutex);
|
||||
}
|
||||
|
||||
if (data->window_surface)
|
||||
wayland_window_surface_update_wayland_surface(data->window_surface, surface);
|
||||
|
||||
out:
|
||||
TRACE("hwnd=%p surface=%p=>%p\n", data->hwnd, data->wayland_surface, surface);
|
||||
data->wayland_surface = surface;
|
||||
|
|
|
@ -36,6 +36,7 @@ struct wayland_window_surface
|
|||
{
|
||||
struct window_surface header;
|
||||
HWND hwnd;
|
||||
struct wayland_surface *wayland_surface;
|
||||
RECT bounds;
|
||||
void *bits;
|
||||
pthread_mutex_t mutex;
|
||||
|
@ -54,6 +55,15 @@ static inline void reset_bounds(RECT *bounds)
|
|||
bounds->right = bounds->bottom = INT_MIN;
|
||||
}
|
||||
|
||||
static void buffer_release(void *data, struct wl_buffer *buffer)
|
||||
{
|
||||
struct wayland_shm_buffer *shm_buffer = data;
|
||||
TRACE("shm_buffer=%p\n", shm_buffer);
|
||||
wayland_shm_buffer_destroy(shm_buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = { buffer_release };
|
||||
|
||||
/***********************************************************************
|
||||
* wayland_window_surface_lock
|
||||
*/
|
||||
|
@ -108,7 +118,46 @@ static void wayland_window_surface_set_region(struct window_surface *window_surf
|
|||
*/
|
||||
static void wayland_window_surface_flush(struct window_surface *window_surface)
|
||||
{
|
||||
/* TODO */
|
||||
struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface);
|
||||
struct wayland_shm_buffer *shm_buffer;
|
||||
BOOL flushed = FALSE;
|
||||
|
||||
wayland_window_surface_lock(window_surface);
|
||||
|
||||
if (IsRectEmpty(&wws->bounds)) goto done;
|
||||
|
||||
if (!wws->wayland_surface)
|
||||
{
|
||||
ERR("missing wayland surface, returning\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
TRACE("surface=%p hwnd=%p surface_rect=%s bounds=%s\n", wws, wws->hwnd,
|
||||
wine_dbgstr_rect(&wws->header.rect), wine_dbgstr_rect(&wws->bounds));
|
||||
|
||||
shm_buffer = wayland_shm_buffer_create(wws->info.bmiHeader.biWidth,
|
||||
abs(wws->info.bmiHeader.biHeight),
|
||||
WL_SHM_FORMAT_XRGB8888);
|
||||
if (!shm_buffer)
|
||||
{
|
||||
ERR("failed to create Wayland SHM buffer, returning\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
wl_buffer_add_listener(shm_buffer->wl_buffer, &buffer_listener, shm_buffer);
|
||||
|
||||
memcpy(shm_buffer->map_data, wws->bits, shm_buffer->map_size);
|
||||
|
||||
pthread_mutex_lock(&wws->wayland_surface->mutex);
|
||||
wayland_surface_attach_shm(wws->wayland_surface, shm_buffer);
|
||||
wl_surface_commit(wws->wayland_surface->wl_surface);
|
||||
pthread_mutex_unlock(&wws->wayland_surface->mutex);
|
||||
wl_display_flush(process_wayland.wl_display);
|
||||
flushed = TRUE;
|
||||
|
||||
done:
|
||||
if (flushed) reset_bounds(&wws->bounds);
|
||||
wayland_window_surface_unlock(window_surface);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -182,3 +231,20 @@ failed:
|
|||
wayland_window_surface_destroy(&wws->header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* wayland_window_surface_update_wayland_surface
|
||||
*/
|
||||
void wayland_window_surface_update_wayland_surface(struct window_surface *window_surface,
|
||||
struct wayland_surface *wayland_surface)
|
||||
{
|
||||
struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface);
|
||||
|
||||
wayland_window_surface_lock(window_surface);
|
||||
|
||||
TRACE("surface=%p hwnd=%p wayland_surface=%p\n", wws, wws->hwnd, wayland_surface);
|
||||
|
||||
wws->wayland_surface = wayland_surface;
|
||||
|
||||
wayland_window_surface_unlock(window_surface);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue