parent
33bea964ca
commit
a67a71a7cf
@ -1,17 +1,24 @@ |
||||
CFLAGS = -Wall -g $(shell pkg-config --cflags libffi)
|
||||
LDLIBS = $(shell pkg-config --libs libffi)
|
||||
CFLAGS += -Wall -g $(shell pkg-config --cflags libffi libdrm)
|
||||
LDLIBS += $(shell pkg-config --libs libffi libdrm)
|
||||
|
||||
all : wayland client |
||||
|
||||
wayland_objs = wayland.o event-loop.o hash.o
|
||||
wayland_objs = wayland.o event-loop.o hash.o compositor.o
|
||||
|
||||
wayland : $(wayland_objs) |
||||
gcc -o $@ $(wayland_objs) $(LDLIBS)
|
||||
|
||||
libwayland_objs = wayland-client.o
|
||||
|
||||
libwayland.so : $(libwayland_objs) |
||||
gcc -o $@ $(libwayland_objs) -shared
|
||||
|
||||
client_objs = client.o
|
||||
client : CFLAGS += $(shell pkg-config --cflags cairo) |
||||
client : LDLIBS += $(shell pkg-config --libs cairo) |
||||
|
||||
client : $(client_objs) |
||||
gcc -o $@ $(client_objs)
|
||||
client : $(client_objs) libwayland.so |
||||
gcc -o $@ -L. -lwayland $(LDLIBS) $(client_objs)
|
||||
|
||||
clean : |
||||
rm client wayland *.o
|
||||
rm -f client wayland *.o libwayland.so
|
@ -1,109 +1,135 @@ |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <i915_drm.h> |
||||
#include <sys/ioctl.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/un.h> |
||||
#include <ctype.h> |
||||
#include <math.h> |
||||
#include <cairo.h> |
||||
|
||||
#include "wayland-client.h" |
||||
|
||||
static const char gem_device[] = "/dev/dri/card0"; |
||||
static const char socket_name[] = "\0wayland"; |
||||
|
||||
struct method { |
||||
const char *name; |
||||
uint32_t opcode; |
||||
}; |
||||
|
||||
static const struct method display_methods[] = { |
||||
{ "get_interface", 0 }, |
||||
{ "create_surface", 1 }, |
||||
{ NULL } |
||||
}; |
||||
|
||||
static const struct method surface_methods[] = { |
||||
{ "get_interface", 0 }, |
||||
{ "post", 1 }, |
||||
{ NULL } |
||||
}; |
||||
|
||||
struct interface { |
||||
const char *name; |
||||
const struct method *methods; |
||||
}; |
||||
|
||||
static const struct interface interfaces[] = { |
||||
{ "display", display_methods }, |
||||
{ "surface", surface_methods }, |
||||
{ NULL }, |
||||
}; |
||||
|
||||
int send_request(int sock, const char *buffer, int buffer_len) |
||||
static uint32_t name_cairo_surface(int fd, cairo_surface_t *surface) |
||||
{ |
||||
const struct method *methods; |
||||
char interface[32], method[32]; |
||||
uint32_t request[3], id, new_id; |
||||
int i; |
||||
|
||||
if (sscanf(buffer, "%d/%32[^:]:%32s %d\n", |
||||
&id, interface, method, &new_id) != 4) { |
||||
printf("invalid input, expected <id>/<interface>:<method>\n"); |
||||
return -1; |
||||
} |
||||
struct drm_i915_gem_create create; |
||||
struct drm_gem_flink flink; |
||||
struct drm_i915_gem_pwrite pwrite; |
||||
int32_t width, height, stride; |
||||
|
||||
width = cairo_image_surface_get_width(surface); |
||||
height = cairo_image_surface_get_height(surface); |
||||
stride = cairo_image_surface_get_stride(surface); |
||||
|
||||
printf("got object id %d, interface \"%s\", name \"%s\"\n", |
||||
id, interface, method); |
||||
memset(&create, 0, sizeof(create)); |
||||
create.size = height * stride; |
||||
|
||||
for (i = 0; interfaces[i].name != NULL; i++) { |
||||
if (strcmp(interfaces[i].name, interface) == 0) |
||||
break; |
||||
if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) { |
||||
fprintf(stderr, "gem create failed: %m\n"); |
||||
return 0; |
||||
} |
||||
if (interfaces[i].name == NULL) { |
||||
printf("unknown interface \"%s\"\n", interface); |
||||
return -1; |
||||
|
||||
pwrite.handle = create.handle; |
||||
pwrite.offset = 0; |
||||
pwrite.size = height * stride; |
||||
pwrite.data_ptr = (uint64_t) (uintptr_t) |
||||
cairo_image_surface_get_data(surface); |
||||
if (ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite) < 0) { |
||||
fprintf(stderr, "gem pwrite failed: %m\n"); |
||||
return 0; |
||||
} |
||||
|
||||
methods = interfaces[i].methods; |
||||
for (i = 0; methods[i].name != NULL; i++) { |
||||
if (strcmp(methods[i].name, method) == 0) |
||||
break; |
||||
flink.handle = create.handle; |
||||
if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) { |
||||
fprintf(stderr, "gem flink failed: %m\n"); |
||||
return 0; |
||||
} |
||||
|
||||
if (methods[i].name == NULL) { |
||||
printf("unknown request \"%s\"\n", method); |
||||
return -1; |
||||
#if 0 |
||||
/* We need to hold on to the handle until the server has received
|
||||
* the attach request... we probably need a confirmation event. |
||||
* I guess the breadcrumb idea will suffice. */ |
||||
struct drm_gem_close close; |
||||
close.handle = create.handle; |
||||
if (ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) { |
||||
fprintf(stderr, "gem close failed: %m\n"); |
||||
return 0; |
||||
} |
||||
#endif |
||||
|
||||
request[0] = id; |
||||
request[1] = methods[i].opcode; |
||||
request[2] = new_id; |
||||
return flink.name; |
||||
} |
||||
|
||||
return write(sock, request, sizeof request); |
||||
static void * |
||||
draw_stuff(int width, int height) |
||||
{ |
||||
cairo_surface_t *surface; |
||||
cairo_t *cr; |
||||
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, |
||||
width, height); |
||||
|
||||
cr = cairo_create(surface); |
||||
|
||||
cairo_arc(cr, width / 2, height / 2, width / 2 - 10, 0, 2 * M_PI); |
||||
cairo_set_source_rgb(cr, 1, 0, 0); |
||||
cairo_fill_preserve(cr); |
||||
cairo_set_source_rgb(cr, 1, 1, 0); |
||||
cairo_stroke(cr); |
||||
|
||||
cairo_arc(cr, width / 2, height / 2, width / 4 - 10, 0, 2 * M_PI); |
||||
cairo_set_source_rgb(cr, 0, 0, 1); |
||||
cairo_fill_preserve(cr); |
||||
cairo_set_source_rgb(cr, 1, 1, 0); |
||||
cairo_stroke(cr); |
||||
|
||||
cairo_destroy(cr); |
||||
|
||||
return surface; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
struct sockaddr_un name; |
||||
socklen_t size; |
||||
int sock, len; |
||||
char buffer[256]; |
||||
struct wl_connection *connection; |
||||
struct wl_display *display; |
||||
struct wl_surface *surface; |
||||
int width = 300, height = 300, fd; |
||||
uint32_t name; |
||||
cairo_surface_t *s; |
||||
|
||||
fd = open(gem_device, O_RDWR); |
||||
if (fd < 0) { |
||||
fprintf(stderr, "drm open failed: %m\n"); |
||||
return -1; |
||||
} |
||||
|
||||
sock = socket(PF_LOCAL, SOCK_STREAM, 0); |
||||
if (sock < 0) |
||||
connection = wl_connection_create(socket_name); |
||||
if (connection == NULL) { |
||||
fprintf(stderr, "failed to create connection: %m\n"); |
||||
return -1; |
||||
} |
||||
|
||||
name.sun_family = AF_LOCAL; |
||||
memcpy(name.sun_path, socket_name, sizeof socket_name); |
||||
display = wl_connection_get_display(connection); |
||||
|
||||
size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name; |
||||
surface = wl_display_create_surface(display); |
||||
|
||||
if (connect (sock, (struct sockaddr *) &name, size) < 0) |
||||
s = draw_stuff(width, height); |
||||
name = name_cairo_surface(fd, s); |
||||
|
||||
wl_surface_attach(surface, name, width, height, |
||||
cairo_image_surface_get_stride(s)); |
||||
|
||||
if (wl_connection_flush(connection) < 0) { |
||||
fprintf(stderr, "flush error: %m\n"); |
||||
return -1; |
||||
} |
||||
|
||||
while (len = read(STDIN_FILENO, buffer, sizeof buffer), len > 0) |
||||
if (send_request(sock, buffer, len) < 0) |
||||
break; |
||||
while (1) |
||||
wl_connection_iterate(connection); |
||||
|
||||
return 0; |
||||
} |
||||
|
@ -0,0 +1,131 @@ |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <i915_drm.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/mman.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <linux/fb.h> |
||||
|
||||
#include "wayland.h" |
||||
|
||||
struct lame_compositor { |
||||
struct wl_compositor base; |
||||
void *fb; |
||||
int32_t width, height, stride; |
||||
int gem_fd; |
||||
}; |
||||
|
||||
void notify_surface_create(struct wl_compositor *compositor, |
||||
struct wl_surface *surface) |
||||
{ |
||||
} |
||||
|
||||
void notify_surface_attach(struct wl_compositor *compositor, |
||||
struct wl_surface *surface, uint32_t name,
|
||||
uint32_t width, uint32_t height, uint32_t stride) |
||||
{ |
||||
struct lame_compositor *lc = (struct lame_compositor *) compositor; |
||||
struct drm_i915_gem_pread pread; |
||||
struct drm_gem_open open_arg; |
||||
struct drm_gem_close close_arg; |
||||
char *data, *dst; |
||||
int i, ret, x = 600, y = 200; |
||||
|
||||
open_arg.name = name; |
||||
ret = ioctl(lc->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg); |
||||
if (ret != 0) { |
||||
fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, lc->gem_fd); |
||||
return; |
||||
} |
||||
|
||||
data = malloc(open_arg.size); |
||||
if (data == NULL) { |
||||
fprintf(stderr, "swap buffers malloc failed\n"); |
||||
return; |
||||
} |
||||
|
||||
pread.size = open_arg.size; |
||||
pread.handle = open_arg.handle; |
||||
pread.pad = 0; |
||||
pread.offset = 0; |
||||
pread.size = stride * height; |
||||
pread.data_ptr = (long) data; |
||||
|
||||
if (ioctl(lc->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) { |
||||
fprintf(stderr, "gem pread failed"); |
||||
return; |
||||
} |
||||
|
||||
dst = lc->fb + lc->stride * y + x * 4; |
||||
for (i = 0; i < height; i++) |
||||
memcpy(dst + lc->stride * i, data + stride * i, width * 4); |
||||
|
||||
close_arg.handle = open_arg.handle; |
||||
ret = ioctl(lc->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg); |
||||
if (ret != 0) { |
||||
fprintf(stderr, "failed to gem_close name %d: %m\n", name); |
||||
} |
||||
|
||||
free(data); |
||||
} |
||||
|
||||
struct wl_compositor_interface interface = { |
||||
notify_surface_create, |
||||
notify_surface_attach |
||||
}; |
||||
|
||||
static const char fb_device[] = "/dev/fb"; |
||||
static const char gem_device[] = "/dev/dri/card0"; |
||||
|
||||
struct wl_compositor * |
||||
wl_compositor_create(void) |
||||
{ |
||||
struct lame_compositor *lc; |
||||
struct fb_fix_screeninfo fix; |
||||
struct fb_var_screeninfo var; |
||||
int fd; |
||||
|
||||
lc = malloc(sizeof *lc); |
||||
if (lc == NULL) |
||||
return NULL; |
||||
|
||||
lc->base.interface = &interface; |
||||
|
||||
fd = open(fb_device, O_RDWR); |
||||
if (fd < 0) { |
||||
fprintf(stderr, "open %s failed: %m\n", fb_device); |
||||
return NULL; |
||||
} |
||||
|
||||
if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) { |
||||
fprintf(stderr, "fb get fixed failed\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) { |
||||
fprintf(stderr, "fb get fixed failed\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
lc->stride = fix.line_length; |
||||
lc->width = var.xres; |
||||
lc->height = var.yres; |
||||
lc->fb = mmap(NULL, lc->stride * lc->height, |
||||
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
||||
close(fd); |
||||
if (lc->fb == MAP_FAILED) { |
||||
fprintf(stderr, "fb map failed\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
lc->gem_fd = open(gem_device, O_RDWR); |
||||
if (lc->gem_fd < 0) { |
||||
fprintf(stderr, "failed to open drm device\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
return &lc->base; |
||||
} |
@ -0,0 +1,214 @@ |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/un.h> |
||||
#include <ctype.h> |
||||
#include <sys/poll.h> |
||||
|
||||
static const char socket_name[] = "\0wayland"; |
||||
|
||||
struct wl_buffer { |
||||
char data[4096]; |
||||
int head, tail; |
||||
}; |
||||
|
||||
struct wl_connection { |
||||
int fd; |
||||
struct wl_buffer in, out; |
||||
struct wl_display *display; |
||||
uint32_t id; |
||||
}; |
||||
|
||||
struct wl_proxy { |
||||
struct wl_connection *connection; |
||||
uint32_t id; |
||||
}; |
||||
|
||||
struct wl_display { |
||||
struct wl_proxy proxy; |
||||
}; |
||||
|
||||
struct wl_surface { |
||||
struct wl_proxy proxy; |
||||
}; |
||||
|
||||
struct wl_connection * |
||||
wl_connection_create(const char *address) |
||||
{ |
||||
struct wl_connection *connection; |
||||
struct wl_display *display; |
||||
struct sockaddr_un name; |
||||
socklen_t size; |
||||
char buffer[256]; |
||||
uint32_t id, length; |
||||
|
||||
connection = malloc(sizeof *connection); |
||||
if (connection == NULL) |
||||
return NULL; |
||||
|
||||
memset(connection, 0, sizeof *connection); |
||||
connection->id = 256; /* Need to get our id-range. */ |
||||
connection->fd = socket(PF_LOCAL, SOCK_STREAM, 0); |
||||
if (connection->fd < 0) { |
||||
free(connection); |
||||
return NULL; |
||||
} |
||||
|
||||
name.sun_family = AF_LOCAL; |
||||
memcpy(name.sun_path, address, strlen(address + 1) + 2); |
||||
|
||||
size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name; |
||||
|
||||
if (connect (connection->fd, (struct sockaddr *) &name, size) < 0) { |
||||
close(connection->fd); |
||||
free(connection); |
||||
return NULL; |
||||
} |
||||
|
||||
/* FIXME: actually discover advertised objects here. */ |
||||
read(connection->fd, &id, sizeof id); |
||||
read(connection->fd, &length, sizeof length); |
||||
read(connection->fd, buffer, (length + 3) & ~3); |
||||
|
||||
display = malloc(sizeof *display); |
||||
display->proxy.connection = connection; |
||||
display->proxy.id = id; |
||||
connection->display = display; |
||||
|
||||
return connection; |
||||
} |
||||
|
||||
void |
||||
wl_connection_destroy(struct wl_connection *connection) |
||||
{ |
||||
close(connection->fd); |
||||
free(connection->display); |
||||
free(connection); |
||||
} |
||||
|
||||
int |
||||
wl_connection_get_fd(struct wl_connection *connection) |
||||
{ |
||||
return connection->fd; |
||||
} |
||||
|
||||
static void |
||||
handle_event(struct wl_connection *connection) |
||||
{ |
||||
struct wl_buffer *b; |
||||
uint32_t *p, opcode, size; |
||||
|
||||
b = &connection->in; |
||||
p = (uint32_t *) (b->data + b->tail); |
||||
opcode = p[1] & 0xffff; |
||||
size = p[1] >> 16; |
||||
printf("signal from object %d, opcode %d, size %d\n", |
||||
p[0], opcode, size); |
||||
b->tail += size; |
||||
} |
||||
|
||||
void |
||||
wl_connection_iterate(struct wl_connection *connection) |
||||
{ |
||||
struct wl_buffer *b; |
||||
uint32_t *p, opcode, size; |
||||
int len; |
||||
|
||||
b = &connection->in; |
||||
len = read(connection->fd, b->data + b->head, sizeof b->data); |
||||
b->head += len; |
||||
while (len > 0) { |
||||
|
||||
if (b->head - b->tail < 8) |
||||
break; |
||||
|
||||
p = (uint32_t *) (b->data + b->tail); |
||||
opcode = p[1] & 0xffff; |
||||
size = p[1] >> 16; |
||||
if (b->head - b->tail < size) |
||||
break; |
||||
|
||||
handle_event(connection); |
||||
} |
||||
|
||||
if (len < 0) { |
||||
fprintf(stderr, "read error: %m\n"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
} |
||||
|
||||
int |
||||
wl_connection_flush(struct wl_connection *connection) |
||||
{ |
||||
struct wl_buffer *b; |
||||
int len; |
||||
|
||||
b = &connection->out; |
||||
if (b->head == b->tail) |
||||
return 0; |
||||
|
||||
len = write(connection->fd, b->data + b->tail, b->head - b->tail); |
||||
b->tail += len; |
||||
|
||||
return len; |
||||
}; |
||||
|
||||
struct wl_display * |
||||
wl_connection_get_display(struct wl_connection *connection) |
||||
{ |
||||
return connection->display; |
||||
} |
||||
|
||||
#define WL_DISPLAY_CREATE_SURFACE 0 |
||||
|
||||
struct wl_surface * |
||||
wl_display_create_surface(struct wl_display *display) |
||||
{ |
||||
struct wl_surface *surface; |
||||
struct wl_connection *connection; |
||||
uint32_t request[3]; |
||||
|
||||
surface = malloc(sizeof *surface); |
||||
if (surface == NULL) |
||||
return NULL; |
||||
|
||||
connection = display->proxy.connection; |
||||
surface->proxy.id = connection->id++; |
||||
surface->proxy.connection = connection; |
||||
|
||||
request[0] = display->proxy.id; |
||||
request[1] = WL_DISPLAY_CREATE_SURFACE | ((sizeof request) << 16); |
||||
request[2] = surface->proxy.id; |
||||
|
||||
memcpy(connection->out.data + connection->out.head, |
||||
request, sizeof request); |
||||
connection->out.head += sizeof request; |
||||
|
||||
return surface; |
||||
} |
||||
|
||||
#define WL_SURFACE_ATTACH 0 |
||||
|
||||
void wl_surface_attach(struct wl_surface *surface, |
||||
uint32_t name, int width, int height, int stride) |
||||
{ |
||||
uint32_t request[6]; |
||||
struct wl_connection *connection; |
||||
|
||||
request[0] = surface->proxy.id; |
||||
request[1] = WL_SURFACE_ATTACH | ((sizeof request) << 16); |
||||
request[2] = name; |
||||
request[3] = width; |
||||
request[4] = height; |
||||
request[5] = stride; |
||||
|
||||
connection = surface->proxy.connection; |
||||
memcpy(connection->out.data + connection->out.head, |
||||
request, sizeof request); |
||||
connection->out.head += sizeof request; |
||||
} |
@ -0,0 +1,28 @@ |
||||
#ifndef _WAYLAND_CLIENT_H |
||||
#define _WAYLAND_CLIENT_H |
||||
|
||||
struct wl_connection; |
||||
struct wl_display; |
||||
struct wl_surface; |
||||
|
||||
struct wl_connection * |
||||
wl_connection_create(const char *address); |
||||
void |
||||
wl_connection_destroy(struct wl_connection *connection); |
||||
int |
||||
wl_connection_get_fd(struct wl_connection *connection); |
||||
void |
||||
wl_connection_iterate(struct wl_connection *connection); |
||||
int |
||||
wl_connection_flush(struct wl_connection *connection); |
||||
|
||||
struct wl_display * |
||||
wl_connection_get_display(struct wl_connection *connection); |
||||
struct wl_surface * |
||||
wl_display_create_surface(struct wl_display *display); |
||||
|
||||
void |
||||
wl_surface_attach(struct wl_surface *surface, |
||||
uint32_t name, int width, int height, int stride); |
||||
|
||||
#endif |
Loading…
Reference in new issue