Commit 6b0a84c8 authored by Alexandros Frantzis's avatar Alexandros Frantzis Committed by Alexandre Julliard

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.
parent d53cb720
......@@ -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, &section_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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment