broadway: Add support for uploading textures to daemon

This commit is contained in:
Alexander Larsson 2017-11-17 16:40:06 +01:00
parent f31d7e1f91
commit 48d587d255
4 changed files with 194 additions and 2 deletions

View File

@ -157,7 +157,9 @@ typedef enum {
BROADWAY_REQUEST_GRAB_POINTER,
BROADWAY_REQUEST_UNGRAB_POINTER,
BROADWAY_REQUEST_FOCUS_WINDOW,
BROADWAY_REQUEST_SET_SHOW_KEYBOARD
BROADWAY_REQUEST_SET_SHOW_KEYBOARD,
BROADWAY_REQUEST_UPLOAD_TEXTURE,
BROADWAY_REQUEST_RELEASE_TEXTURE,
} BroadwayRequestType;
typedef struct {
@ -194,6 +196,18 @@ typedef struct {
guint32 height;
} BroadwayRequestUpdate;
typedef struct {
BroadwayRequestBase base;
guint32 id;
guint32 offset;
guint32 size;
} BroadwayRequestUploadTexture;
typedef struct {
BroadwayRequestBase base;
guint32 id;
} BroadwayRequestReleaseTexture;
typedef struct {
BroadwayRequestBase base;
guint32 id;
@ -248,6 +262,8 @@ typedef union {
BroadwayRequestTranslate translate;
BroadwayRequestFocusWindow focus_window;
BroadwayRequestSetShowKeyboard set_show_keyboard;
BroadwayRequestUploadTexture upload_texture;
BroadwayRequestReleaseTexture release_texture;
} BroadwayRequest;
typedef enum {

View File

@ -8,6 +8,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include <errno.h>
#include <glib.h>
#include <gio/gio.h>
@ -56,6 +57,7 @@ typedef struct {
GList *windows;
guint disconnect_idle;
GList *fds;
GHashTable *textures;
} BroadwayClient;
static void
@ -75,6 +77,7 @@ client_free (BroadwayClient *client)
g_string_free (client->buffer, TRUE);
g_slist_free_full (client->serial_mappings, g_free);
g_list_free_full (client->fds, close_fd);
g_hash_table_destroy (client->textures);
g_free (client);
}
@ -218,6 +221,7 @@ client_handle_request (BroadwayClient *client,
BroadwayReplyUngrabPointer reply_ungrab_pointer;
cairo_surface_t *surface;
guint32 before_serial, now_serial;
int fd;
before_serial = broadway_server_get_next_serial (server);
@ -286,6 +290,54 @@ client_handle_request (BroadwayClient *client,
cairo_surface_destroy (surface);
}
break;
case BROADWAY_REQUEST_UPLOAD_TEXTURE:
if (client->fds == NULL)
g_warning ("FD passing mismatch");
else
{
char *data, *p;
gsize to_read;
gssize num_read;
GBytes *texture;
fd = GPOINTER_TO_INT (client->fds->data);
client->fds = g_list_delete_link (client->fds, client->fds);
data = g_malloc (request->upload_texture.size);
to_read = request->upload_texture.size;
lseek (fd, request->upload_texture.offset, SEEK_SET);
p = data;
do
{
num_read = read (fd, p, to_read);
if (num_read == -1 && errno == EAGAIN)
continue;
if (num_read > 0)
{
p += num_read;
to_read -= num_read;
}
else
{
g_warning ("Unexpected short read of texture");
break;
}
}
while (to_read > 0);
close (fd);
texture = g_bytes_new_take (data, request->upload_texture.size);
g_hash_table_replace (client->textures,
GINT_TO_POINTER (request->release_texture.id),
texture);
}
break;
case BROADWAY_REQUEST_RELEASE_TEXTURE:
g_hash_table_remove (client->textures, GINT_TO_POINTER (request->release_texture.id));
break;
case BROADWAY_REQUEST_MOVE_RESIZE:
broadway_server_window_move_resize (server,
request->move_resize.id,
@ -429,6 +481,7 @@ incoming_client (GSocketService *service,
client = g_new0 (BroadwayClient, 1);
client->id = client_id_count++;
client->connection = g_object_ref (connection);
client->textures = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_bytes_unref);
input = g_io_stream_get_input_stream (G_IO_STREAM (client->connection));
client->in = input;

View File

@ -1,5 +1,9 @@
#include "config.h"
#ifdef HAVE_LINUX_MEMFD_H
#include <linux/memfd.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
@ -9,6 +13,7 @@
#include "gdkbroadway-server.h"
#include "gdkprivate-broadway.h"
#include <gdk/gdktextureprivate.h>
#include <glib.h>
#include <glib/gprintf.h>
@ -35,6 +40,7 @@ struct _GdkBroadwayServer {
GObject parent_instance;
guint32 next_serial;
guint32 next_texture_id;
GSocketConnection *connection;
guint32 recv_buffer_size;
@ -197,7 +203,6 @@ gdk_broadway_server_send_message_with_size (GdkBroadwayServer *server, BroadwayR
exit (1);
}
g_print ("socket send message wrote %d of %d\n", (int)bytes_written, (int)size);
buf += bytes_written;
size -= bytes_written;
@ -775,6 +780,120 @@ _gdk_broadway_server_window_update (GdkBroadwayServer *server,
BROADWAY_REQUEST_UPDATE);
}
static int
open_shared_memory (void)
{
static gboolean force_shm_open = FALSE;
int ret = -1;
#if !defined (__NR_memfd_create)
force_shm_open = TRUE;
#endif
do
{
#if defined (__NR_memfd_create)
if (!force_shm_open)
{
ret = syscall (__NR_memfd_create, "gdk-broadway", MFD_CLOEXEC);
/* fall back to shm_open until debian stops shipping 3.16 kernel
* See bug 766341
*/
if (ret < 0 && errno == ENOSYS)
force_shm_open = TRUE;
}
#endif
if (force_shm_open)
{
char name[NAME_MAX - 1] = "";
sprintf (name, "/gdk-broadway-%x", g_random_int ());
ret = shm_open (name, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);
if (ret >= 0)
shm_unlink (name);
else if (errno == EEXIST)
continue;
}
}
while (ret < 0 && errno == EINTR);
if (ret < 0)
g_critical (G_STRLOC ": creating shared memory file (using %s) failed: %m",
force_shm_open? "shm_open" : "memfd_create");
return ret;
}
typedef struct {
int fd;
gsize size;
} PngData;
static cairo_status_t
write_png_cb (void *closure,
const guchar *data,
unsigned int length)
{
PngData *png_data = closure;
int fd = png_data->fd;
while (length)
{
gssize ret = write (fd, data, length);
if (ret <= 0)
return CAIRO_STATUS_WRITE_ERROR;
png_data->size += ret;
length -= ret;
data += ret;
}
return CAIRO_STATUS_SUCCESS;
}
guint32
gdk_broadway_server_upload_texture (GdkBroadwayServer *server,
GdkTexture *texture)
{
guint32 id;
cairo_surface_t *surface = gdk_texture_download_surface (texture);
BroadwayRequestUploadTexture msg;
PngData data;
id = ++server->next_texture_id;
data.fd = open_shared_memory ();
data.size = 0;
cairo_surface_write_to_png_stream (surface, write_png_cb, &data);
msg.id = id;
msg.offset = 0;
msg.size = data.size;
/* This passes ownership of fd */
gdk_broadway_server_send_fd_message (server, msg,
BROADWAY_REQUEST_UPLOAD_TEXTURE, data.fd);
return id;
}
void
gdk_broadway_server_release_texture (GdkBroadwayServer *server,
guint32 id)
{
BroadwayRequestReleaseTexture msg;
msg.id = id;
gdk_broadway_server_send_message (server, msg,
BROADWAY_REQUEST_RELEASE_TEXTURE);
}
gboolean
_gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
gint id,

View File

@ -59,6 +59,10 @@ gboolean _gdk_broadway_server_window_translate (GdkBroadwaySer
cairo_region_t *area,
gint dx,
gint dy);
guint32 gdk_broadway_server_upload_texture (GdkBroadwayServer *server,
GdkTexture *texture);
void gdk_broadway_server_release_texture (GdkBroadwayServer *server,
guint32 id);
cairo_surface_t *_gdk_broadway_server_create_surface (int width,
int height);
void _gdk_broadway_server_window_update (GdkBroadwayServer *server,