aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arg.h63
-rw-r--r--src/st.c4354
-rw-r--r--src/wld/.gitignore11
-rw-r--r--src/wld/COPYING20
-rw-r--r--src/wld/Makefile186
-rw-r--r--src/wld/README.md16
-rw-r--r--src/wld/TODO6
-rw-r--r--src/wld/buffer.c137
-rw-r--r--src/wld/buffered_surface.c224
-rw-r--r--src/wld/color.c850
-rw-r--r--src/wld/common.mk11
-rw-r--r--src/wld/config.mk20
-rw-r--r--src/wld/context.c70
-rw-r--r--src/wld/drm-private.h46
-rw-r--r--src/wld/drm.c98
-rw-r--r--src/wld/drm.h52
-rw-r--r--src/wld/dumb.c235
-rw-r--r--src/wld/font.c235
-rw-r--r--src/wld/intel.c390
-rw-r--r--src/wld/intel/batch.c99
-rw-r--r--src/wld/intel/batch.h104
-rw-r--r--src/wld/intel/blt.h347
-rw-r--r--src/wld/intel/i965_pci_ids.h93
-rw-r--r--src/wld/intel/local.mk6
-rw-r--r--src/wld/intel/mi.h50
-rw-r--r--src/wld/interface/buffer.h33
-rw-r--r--src/wld/interface/context.h50
-rw-r--r--src/wld/interface/drm.h43
-rw-r--r--src/wld/interface/renderer.h68
-rw-r--r--src/wld/interface/surface.h41
-rw-r--r--src/wld/interface/wayland.h41
-rw-r--r--src/wld/nouveau/g80_2d.xml.h547
-rw-r--r--src/wld/nouveau/g80_defs.xml.h382
-rw-r--r--src/wld/nouveau/nouveau.c678
-rw-r--r--src/wld/nouveau/nv_object.xml.h452
-rw-r--r--src/wld/pixman.c450
-rw-r--r--src/wld/pixman.h44
-rw-r--r--src/wld/protocol/local.mk18
-rw-r--r--src/wld/protocol/wayland-drm.xml185
-rw-r--r--src/wld/renderer.c157
-rw-r--r--src/wld/surface.c70
-rw-r--r--src/wld/wayland-drm.c296
-rw-r--r--src/wld/wayland-private.h60
-rw-r--r--src/wld/wayland-shm.c294
-rw-r--r--src/wld/wayland.c308
-rw-r--r--src/wld/wayland.h84
-rw-r--r--src/wld/wld-private.h243
-rw-r--r--src/wld/wld.h283
-rw-r--r--src/wld/wld.pc.in13
49 files changed, 12563 insertions, 0 deletions
diff --git a/src/arg.h b/src/arg.h
new file mode 100644
index 0000000..4df77a7
--- /dev/null
+++ b/src/arg.h
@@ -0,0 +1,63 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H__
+#define ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][1]\
+ && argv[0][0] == '-';\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM case '0':\
+ case '1':\
+ case '2':\
+ case '3':\
+ case '4':\
+ case '5':\
+ case '6':\
+ case '7':\
+ case '8':\
+ case '9'
+
+#define ARGEND }\
+ }
+
+#define ARGC() argc_
+
+#define ARGNUMF(base) (brk_ = 1, estrtol(argv[0], (base)))
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#endif
diff --git a/src/st.c b/src/st.c
new file mode 100644
index 0000000..ba550ce
--- /dev/null
+++ b/src/st.c
@@ -0,0 +1,4354 @@
+/* See LICENSE for license details. */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+/* for BTN_* definitions */
+#include <linux/input.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <wayland-client.h>
+#include <wayland-cursor.h>
+#include <xkbcommon/xkbcommon.h>
+#include "wld/wld.h"
+#include "wld/wayland.h"
+#include <fontconfig/fontconfig.h>
+#include <wchar.h>
+
+#include "arg.h"
+#include "xdg-shell.h"
+
+char *argv0;
+
+#if defined(__linux)
+ #include <pty.h>
+#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+ #include <util.h>
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ #include <libutil.h>
+#endif
+
+
+/* Arbitrary sizes */
+#define UTF_INVALID 0xFFFD
+#define UTF_SIZ 4
+#define ESC_BUF_SIZ (128*UTF_SIZ)
+#define ESC_ARG_SIZ 16
+#define STR_BUF_SIZ ESC_BUF_SIZ
+#define STR_ARG_SIZ ESC_ARG_SIZ
+#define DRAW_BUF_SIZ 20*1024
+#define XK_ANY_MOD UINT_MAX
+#define XK_NO_MOD 0
+#define XK_SWITCH_MOD (1<<13)
+
+#define MOD_MASK_ANY UINT_MAX
+#define MOD_MASK_NONE 0
+#define MOD_MASK_CTRL (1<<0)
+#define MOD_MASK_ALT (1<<1)
+#define MOD_MASK_SHIFT (1<<2)
+#define MOD_MASK_LOGO (1<<3)
+
+#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL
+#define AXIS_HORIZONTAL WL_POINTER_AXIS_HORIZONTAL_SCROLL
+
+/* macros */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a) / sizeof(a)[0])
+#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
+#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
+#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL)
+#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
+#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
+ (a).bg != (b).bg)
+#define IS_SET(flag) ((term.mode & (flag)) != 0)
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
+ (t1.tv_nsec-t2.tv_nsec)/1E6)
+#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
+
+#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x) (1 << 24 & (x))
+#define TRUERED(x) (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x) (((x) & 0xff00))
+#define TRUEBLUE(x) (((x) & 0xff) << 8)
+
+
+enum glyph_attribute {
+ ATTR_NULL = 0,
+ ATTR_BOLD = 1 << 0,
+ ATTR_FAINT = 1 << 1,
+ ATTR_ITALIC = 1 << 2,
+ ATTR_UNDERLINE = 1 << 3,
+ ATTR_BLINK = 1 << 4,
+ ATTR_REVERSE = 1 << 5,
+ ATTR_INVISIBLE = 1 << 6,
+ ATTR_STRUCK = 1 << 7,
+ ATTR_WRAP = 1 << 8,
+ ATTR_WIDE = 1 << 9,
+ ATTR_WDUMMY = 1 << 10,
+ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+};
+
+enum cursor_movement {
+ CURSOR_SAVE,
+ CURSOR_LOAD
+};
+
+enum cursor_state {
+ CURSOR_DEFAULT = 0,
+ CURSOR_WRAPNEXT = 1,
+ CURSOR_ORIGIN = 2
+};
+
+enum term_mode {
+ MODE_WRAP = 1 << 0,
+ MODE_INSERT = 1 << 1,
+ MODE_APPKEYPAD = 1 << 2,
+ MODE_ALTSCREEN = 1 << 3,
+ MODE_CRLF = 1 << 4,
+ MODE_MOUSEBTN = 1 << 5,
+ MODE_MOUSEMOTION = 1 << 6,
+ MODE_REVERSE = 1 << 7,
+ MODE_KBDLOCK = 1 << 8,
+ MODE_HIDE = 1 << 9,
+ MODE_ECHO = 1 << 10,
+ MODE_APPCURSOR = 1 << 11,
+ MODE_MOUSESGR = 1 << 12,
+ MODE_8BIT = 1 << 13,
+ MODE_BLINK = 1 << 14,
+ MODE_FBLINK = 1 << 15,
+ MODE_FOCUS = 1 << 16,
+ MODE_MOUSEX10 = 1 << 17,
+ MODE_MOUSEMANY = 1 << 18,
+ MODE_BRCKTPASTE = 1 << 19,
+ MODE_PRINT = 1 << 20,
+ MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+ |MODE_MOUSEMANY,
+};
+
+enum charset {
+ CS_GRAPHIC0,
+ CS_GRAPHIC1,
+ CS_UK,
+ CS_USA,
+ CS_MULTI,
+ CS_GER,
+ CS_FIN
+};
+
+enum escape_state {
+ ESC_START = 1,
+ ESC_CSI = 2,
+ ESC_STR = 4, /* DCS, OSC, PM, APC */
+ ESC_ALTCHARSET = 8,
+ ESC_STR_END = 16, /* a final string was encountered */
+ ESC_TEST = 32, /* Enter in test mode */
+};
+
+enum window_state {
+ WIN_VISIBLE = 1,
+ WIN_FOCUSED = 2
+};
+
+enum selection_mode {
+ SEL_IDLE = 0,
+ SEL_EMPTY = 1,
+ SEL_READY = 2
+};
+
+enum selection_type {
+ SEL_REGULAR = 1,
+ SEL_RECTANGULAR = 2
+};
+
+enum selection_snap {
+ SNAP_WORD = 1,
+ SNAP_LINE = 2
+};
+
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+typedef uint_least32_t Rune;
+
+typedef struct {
+ Rune u; /* character code */
+ ushort mode; /* attribute flags */
+ uint32_t fg; /* foreground */
+ uint32_t bg; /* background */
+} Glyph;
+
+typedef Glyph *Line;
+
+typedef struct {
+ Glyph attr; /* current char attributes */
+ int x;
+ int y;
+ char state;
+} TCursor;
+
+/* CSI Escape sequence structs */
+/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
+typedef struct {
+ char buf[ESC_BUF_SIZ]; /* raw string */
+ int len; /* raw string length */
+ char priv;
+ int arg[ESC_ARG_SIZ];
+ int narg; /* nb of args */
+ char mode[2];
+} CSIEscape;
+
+/* STR Escape sequence structs */
+/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
+typedef struct {
+ char type; /* ESC type ... */
+ char buf[STR_BUF_SIZ]; /* raw string */
+ int len; /* raw string length */
+ char *args[STR_ARG_SIZ];
+ int narg; /* nb of args */
+} STREscape;
+
+/* Internal representation of the screen */
+typedef struct {
+ int row; /* nb row */
+ int col; /* nb col */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode flags */
+ int esc; /* escape state flags */
+ char trantbl[4]; /* charset table translation */
+ int charset; /* current charset */
+ int icharset; /* selected charset for sequence */
+ int numlock; /* lock numbers in keyboard */
+ int *tabs;
+} Term;
+
+typedef struct {
+ struct xkb_context *ctx;
+ struct xkb_keymap *keymap;
+ struct xkb_state *state;
+ xkb_mod_index_t ctrl, alt, shift, logo;
+ unsigned int mods;
+} XKB;
+
+typedef struct {
+ struct wl_display *dpy;
+ struct wl_compositor *cmp;
+ struct wl_shm *shm;
+ struct wl_seat *seat;
+ struct wl_keyboard *keyboard;
+ struct wl_pointer *pointer;
+ struct wl_data_device_manager *datadevmanager;
+ struct wl_data_device *datadev;
+ struct wl_data_offer *seloffer;
+ struct wl_surface *surface;
+ struct wl_buffer *buffer;
+ struct xdg_shell *shell;
+ struct xdg_surface *xdgsurface;
+ XKB xkb;
+ bool configured;
+ int px, py; /* pointer x and y */
+ int tw, th; /* tty width and height */
+ int w, h; /* window width and height */
+ int ch; /* char height */
+ int cw; /* char width */
+ int vis;
+ char state; /* focus, redraw, visible */
+ int cursor; /* cursor style */
+ struct wl_callback * framecb;
+} Wayland;
+
+typedef struct {
+ struct wld_context *ctx;
+ struct wld_font_context *fontctx;
+ struct wld_renderer *renderer;
+ struct wld_buffer *buffer, *oldbuffer;
+} WLD;
+
+typedef struct {
+ struct wl_cursor_theme *theme;
+ struct wl_cursor *cursor;
+ struct wl_surface *surface;
+} Cursor;
+
+typedef struct {
+ uint b;
+ uint mask;
+ char *s;
+} Mousekey;
+
+typedef struct {
+ int axis;
+ int dir;
+ uint mask;
+ char s[ESC_BUF_SIZ];
+} Axiskey;
+
+typedef struct {
+ xkb_keysym_t k;
+ uint mask;
+ char *s;
+ /* three valued logic variables: 0 indifferent, 1 on, -1 off */
+ signed char appkey; /* application keypad */
+ signed char appcursor; /* application cursor */
+ signed char crlf; /* crlf mode */
+} Key;
+
+typedef struct {
+ int mode;
+ int type;
+ int snap;
+ /*
+ * Selection variables:
+ * nb – normalized coordinates of the beginning of the selection
+ * ne – normalized coordinates of the end of the selection
+ * ob – original coordinates of the beginning of the selection
+ * oe – original coordinates of the end of the selection
+ */
+ struct {
+ int x, y;
+ } nb, ne, ob, oe;
+
+ char *primary;
+ struct wl_data_source *source;
+ int alt;
+ uint32_t tclick1, tclick2;
+} Selection;
+
+typedef union {
+ int i;
+ uint ui;
+ float f;
+ const void *v;
+} Arg;
+
+typedef struct {
+ uint mod;
+ xkb_keysym_t keysym;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Shortcut;
+
+typedef struct {
+ char str[32];
+ uint32_t key;
+ int len;
+ bool started;
+ struct timespec last;
+} Repeat;
+
+/* function definitions used in config.h */
+static void numlock(const Arg *);
+static void selpaste(const Arg *);
+static void wlzoom(const Arg *);
+static void wlzoomabs(const Arg *);
+static void wlzoomreset(const Arg *);
+static void printsel(const Arg *);
+static void printscreen(const Arg *) ;
+static void toggleprinter(const Arg *);
+
+/* Config.h for applying patches and the configuration. */
+#include "config.h"
+
+/* Font structure */
+typedef struct {
+ int height;
+ int width;
+ int ascent;
+ int descent;
+ short lbearing;
+ short rbearing;
+ struct wld_font *match;
+ FcFontSet *set;
+ FcPattern *pattern;
+} Font;
+
+/* Drawing Context */
+typedef struct {
+ uint32_t col[MAX(LEN(colorname), 256)];
+ Font font, bfont, ifont, ibfont;
+} DC;
+
+static void die(const char *, ...);
+static void draw(void);
+static void redraw(void);
+static void drawregion(int, int, int, int);
+static void execsh(void);
+static void stty(void);
+static void sigchld(int);
+static void run(void);
+static void cresize(int, int);
+
+static void csidump(void);
+static void csihandle(void);
+static void csiparse(void);
+static void csireset(void);
+static int eschandle(uchar);
+static void strdump(void);
+static void strhandle(void);
+static void strparse(void);
+static void strreset(void);
+
+static int tattrset(int);
+static void tprinter(char *, size_t);
+static void tdumpsel(void);
+static void tdumpline(int);
+static void tdump(void);
+static void tclearregion(int, int, int, int);
+static void tcursor(int);
+static void tdeletechar(int);
+static void tdeleteline(int);
+static void tinsertblank(int);
+static void tinsertblankline(int);
+static int tlinelen(int);
+static void tmoveto(int, int);
+static void tmoveato(int, int);
+static void tnew(int, int);
+static void tnewline(int);
+static void tputtab(int);
+static void tputc(Rune);
+static void treset(void);
+static void tresize(int, int);
+static void tscrollup(int, int);
+static void tscrolldown(int, int);
+static void tsetattr(int *, int);
+static void tsetchar(Rune, Glyph *, int, int);
+static void tsetscroll(int, int);
+static void tswapscreen(void);
+static void tsetdirt(int, int);
+static void tsetdirtattr(int);
+static void tsetmode(int, int, int *, int);
+static void tfulldirt(void);
+static void techo(Rune);
+static void tcontrolcode(uchar );
+static void tdectest(char );
+static uint32_t tdefcolor(int *, int *, int);
+static void tdeftran(char);
+static inline int match(uint, uint);
+static void ttynew(void);
+static void ttyread(void);
+static void ttyresize(void);
+static void ttysend(char *, size_t);
+static void ttywrite(const char *, size_t);
+static void tstrsequence(uchar);
+
+static inline uchar sixd_to_8bit(int);
+static void wldraws(char *, Glyph, int, int, int, int);
+static void wldrawglyph(Glyph, int, int);
+static void wlclear(int, int, int, int);
+static void wldrawcursor(void);
+static void wlinit(void);
+static void wlloadcols(void);
+static int wlsetcolorname(int, const char *);
+static void wlloadcursor(void);
+static int wlloadfont(Font *, FcPattern *);
+static void wlloadfonts(char *, double);
+static void wlsettitle(char *);
+static void wlresettitle(void);
+static void wlseturgency(int);
+static void wlsetsel(char*, uint32_t);
+static void wltermclear(int, int, int, int);
+static void wlunloadfont(Font *f);
+static void wlunloadfonts(void);
+static void wlresize(int, int);
+
+static void regglobal(void *, struct wl_registry *, uint32_t, const char *,
+ uint32_t);
+static void regglobalremove(void *, struct wl_registry *, uint32_t);
+static void surfenter(void *, struct wl_surface *, struct wl_output *);
+static void surfleave(void *, struct wl_surface *, struct wl_output *);
+static void framedone(void *, struct wl_callback *, uint32_t);
+static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t);
+static void kbdenter(void *, struct wl_keyboard *, uint32_t,
+ struct wl_surface *, struct wl_array *);
+static void kbdleave(void *, struct wl_keyboard *, uint32_t,
+ struct wl_surface *);
+static void kbdkey(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t,
+ uint32_t);
+static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t,
+ uint32_t, uint32_t, uint32_t);
+static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t);
+static void ptrenter(void *, struct wl_pointer *, uint32_t, struct wl_surface *,
+ wl_fixed_t, wl_fixed_t);
+static void ptrleave(void *, struct wl_pointer *, uint32_t,
+ struct wl_surface *);
+static void ptrmotion(void *, struct wl_pointer *, uint32_t,
+ wl_fixed_t, wl_fixed_t);
+static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t,
+ uint32_t, uint32_t);
+static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t,
+ wl_fixed_t);
+static void xdgshellping(void *, struct xdg_shell *, uint32_t);
+static void xdgsurfconfigure(void *, struct xdg_surface *,
+ int32_t, int32_t, struct wl_array *, uint32_t);
+static void xdgsurfclose(void *, struct xdg_surface *);
+static void datadevoffer(void *, struct wl_data_device *,
+ struct wl_data_offer *);
+static void datadeventer(void *, struct wl_data_device *, uint32_t,
+ struct wl_surface *, wl_fixed_t, wl_fixed_t, struct wl_data_offer *);
+static void datadevleave(void *, struct wl_data_device *);
+static void datadevmotion(void *, struct wl_data_device *, uint32_t,
+ wl_fixed_t x, wl_fixed_t y);
+static void datadevdrop(void *, struct wl_data_device *);
+static void datadevselection(void *, struct wl_data_device *,
+ struct wl_data_offer *);
+static void dataofferoffer(void *, struct wl_data_offer *, const char *);
+static void datasrctarget(void *, struct wl_data_source *, const char *);
+static void datasrcsend(void *, struct wl_data_source *, const char *, int32_t);
+static void datasrccancelled(void *, struct wl_data_source *);
+
+static void selinit(void);
+static void selnormalize(void);
+static inline int selected(int, int);
+static char *getsel(void);
+static void selcopy(uint32_t);
+static void selscroll(int, int);
+static void selsnap(int *, int *, int);
+static int x2col(int);
+static int y2row(int);
+
+static size_t utf8decode(char *, Rune *, size_t);
+static Rune utf8decodebyte(char, size_t *);
+static size_t utf8encode(Rune, char *);
+static char utf8encodebyte(Rune, size_t);
+static char *utf8strchr(char *s, Rune u);
+static size_t utf8validate(Rune *, size_t);
+
+static ssize_t xwrite(int, const char *, size_t);
+static void *xmalloc(size_t);
+static void *xrealloc(void *, size_t);
+static char *xstrdup(char *);
+
+static void usage(void);
+
+static struct wl_registry_listener reglistener = { regglobal, regglobalremove };
+static struct wl_surface_listener surflistener = { surfenter, surfleave };
+static struct wl_callback_listener framelistener = { framedone };
+static struct wl_keyboard_listener kbdlistener =
+ { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo };
+static struct wl_pointer_listener ptrlistener =
+ { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis };
+static struct xdg_shell_listener xdgshelllistener = { xdgshellping };
+static struct xdg_surface_listener xdgsurflistener =
+ { xdgsurfconfigure, xdgsurfclose };
+static struct wl_data_device_listener datadevlistener =
+ { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop,
+ datadevselection };
+static struct wl_data_offer_listener dataofferlistener = { dataofferoffer };
+static struct wl_data_source_listener datasrclistener =
+ { datasrctarget, datasrcsend, datasrccancelled };
+
+/* Globals */
+static DC dc;
+static Wayland wl;
+static WLD wld;
+static Cursor cursor;
+static Term term;
+static CSIEscape csiescseq;
+static STREscape strescseq;
+static int cmdfd;
+static pid_t pid;
+static Selection sel;
+static Repeat repeat;
+static bool needdraw = true;
+static int iofd = 1;
+static char **opt_cmd = NULL;
+static char *opt_io = NULL;
+static char *opt_title = NULL;
+static char *opt_embed = NULL;
+static char *opt_class = NULL;
+static char *opt_font = NULL;
+static char *opt_line = NULL;
+static int oldbutton = 3; /* button event on startup: 3 = release */
+static int oldx, oldy;
+static char *usedfont = NULL;
+static double usedfontsize = 0;
+static double defaultfontsize = 0;
+
+static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
+static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
+static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
+static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+
+/* Font Ring Cache */
+enum {
+ FRC_NORMAL,
+ FRC_ITALIC,
+ FRC_BOLD,
+ FRC_ITALICBOLD
+};
+
+typedef struct {
+ struct wld_font *font;
+ int flags;
+ Rune unicodep;
+} Fontcache;
+
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
+
+ssize_t
+xwrite(int fd, const char *s, size_t len)
+{
+ size_t aux = len;
+ ssize_t r;
+
+ while (len > 0) {
+ r = write(fd, s, len);
+ if (r < 0)
+ return r;
+ len -= r;
+ s += r;
+ }
+
+ return aux;
+}
+
+void *
+xmalloc(size_t len)
+{
+ void *p = malloc(len);
+
+ if (!p)
+ die("Out of memory\n");
+
+ return p;
+}
+
+void *
+xrealloc(void *p, size_t len)
+{
+ if ((p = realloc(p, len)) == NULL)
+ die("Out of memory\n");
+
+ return p;
+}
+
+char *
+xstrdup(char *s)
+{
+ if ((s = strdup(s)) == NULL)
+ die("Out of memory\n");
+
+ return s;
+}
+
+size_t
+utf8decode(char *c, Rune *u, size_t clen)
+{
+ size_t i, j, len, type;
+ Rune udecoded;
+
+ *u = UTF_INVALID;
+ if (!clen)
+ return 0;
+ udecoded = utf8decodebyte(c[0], &len);
+ if (!BETWEEN(len, 1, UTF_SIZ))
+ return 1;
+ for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
+ udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
+ if (type != 0)
+ return j;
+ }
+ if (j < len)
+ return 0;
+ *u = udecoded;
+ utf8validate(u, len);
+
+ return len;
+}
+
+Rune
+utf8decodebyte(char c, size_t *i)
+{
+ for (*i = 0; *i < LEN(utfmask); ++(*i))
+ if (((uchar)c & utfmask[*i]) == utfbyte[*i])
+ return (uchar)c & ~utfmask[*i];
+
+ return 0;
+}
+
+size_t
+utf8encode(Rune u, char *c)
+{
+ size_t len, i;
+
+ len = utf8validate(&u, 0);
+ if (len > UTF_SIZ)
+ return 0;
+
+ for (i = len - 1; i != 0; --i) {
+ c[i] = utf8encodebyte(u, 0);
+ u >>= 6;
+ }
+ c[0] = utf8encodebyte(u, len);
+
+ return len;
+}
+
+char
+utf8encodebyte(Rune u, size_t i)
+{
+ return utfbyte[i] | (u & ~utfmask[i]);
+}
+
+char *
+utf8strchr(char *s, Rune u)
+{
+ Rune r;
+ size_t i, j, len;
+
+ len = strlen(s);
+ for (i = 0, j = 0; i < len; i += j) {
+ if (!(j = utf8decode(&s[i], &r, len - i)))
+ break;
+ if (r == u)
+ return &(s[i]);
+ }
+
+ return NULL;
+}
+
+size_t
+utf8validate(Rune *u, size_t i)
+{
+ if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
+ *u = UTF_INVALID;
+ for (i = 1; *u > utfmax[i]; ++i)
+ ;
+
+ return i;
+}
+
+void
+selinit(void)
+{
+ sel.tclick1 = 0;
+ sel.tclick2 = 0;
+ sel.mode = SEL_IDLE;
+ sel.ob.x = -1;
+ sel.primary = NULL;
+ sel.source = NULL;
+}
+
+int
+x2col(int x)
+{
+ x -= borderpx;
+ x /= wl.cw;
+
+ return LIMIT(x, 0, term.col-1);
+}
+
+int
+y2row(int y)
+{
+ y -= borderpx;
+ y /= wl.ch;
+
+ return LIMIT(y, 0, term.row-1);
+}
+
+int
+tlinelen(int y)
+{
+ int i = term.col;
+
+ if (term.line[y][i - 1].mode & ATTR_WRAP)
+ return i;
+
+ while (i > 0 && term.line[y][i - 1].u == ' ')
+ --i;
+
+ return i;
+}
+
+void
+selnormalize(void)
+{
+ int i;
+
+ if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
+ sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
+ sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
+ } else {
+ sel.nb.x = MIN(sel.ob.x, sel.oe.x);
+ sel.ne.x = MAX(sel.ob.x, sel.oe.x);
+ }
+ sel.nb.y = MIN(sel.ob.y, sel.oe.y);
+ sel.ne.y = MAX(sel.ob.y, sel.oe.y);
+
+ selsnap(&sel.nb.x, &sel.nb.y, -1);
+ selsnap(&sel.ne.x, &sel.ne.y, +1);
+
+ /* expand selection over line breaks */
+ if (sel.type == SEL_RECTANGULAR)
+ return;
+ i = tlinelen(sel.nb.y);
+ if (i < sel.nb.x)
+ sel.nb.x = i;
+ if (tlinelen(sel.ne.y) <= sel.ne.x)
+ sel.ne.x = term.col - 1;
+}
+
+int
+selected(int x, int y)
+{
+ if (sel.mode == SEL_EMPTY)
+ return 0;
+
+ if (sel.type == SEL_RECTANGULAR)
+ return BETWEEN(y, sel.nb.y, sel.ne.y)
+ && BETWEEN(x, sel.nb.x, sel.ne.x);
+
+ return BETWEEN(y, sel.nb.y, sel.ne.y)
+ && (y != sel.nb.y || x >= sel.nb.x)
+ && (y != sel.ne.y || x <= sel.ne.x);
+}
+
+void
+selsnap(int *x, int *y, int direction)
+{
+ int newx, newy, xt, yt;
+ int delim, prevdelim;
+ Glyph *gp, *prevgp;
+
+ switch (sel.snap) {
+ case SNAP_WORD:
+ /*
+ * Snap around if the word wraps around at the end or
+ * beginning of a line.
+ */
+ prevgp = &term.line[*y][*x];
+ prevdelim = ISDELIM(prevgp->u);
+ for (;;) {
+ newx = *x + direction;
+ newy = *y;
+ if (!BETWEEN(newx, 0, term.col - 1)) {
+ newy += direction;
+ newx = (newx + term.col) % term.col;
+ if (!BETWEEN(newy, 0, term.row - 1))
+ break;
+
+ if (direction > 0)
+ yt = *y, xt = *x;
+ else
+ yt = newy, xt = newx;
+ if (!(term.line[yt][xt].mode & ATTR_WRAP))
+ break;
+ }
+
+ if (newx >= tlinelen(newy))
+ break;
+
+ gp = &term.line[newy][newx];
+ delim = ISDELIM(gp->u);
+ if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
+ || (delim && gp->u != prevgp->u)))
+ break;
+
+ *x = newx;
+ *y = newy;
+ prevgp = gp;
+ prevdelim = delim;
+ }
+ break;
+ case SNAP_LINE:
+ /*
+ * Snap around if the the previous line or the current one
+ * has set ATTR_WRAP at its end. Then the whole next or
+ * previous line will be selected.
+ */
+ *x = (direction < 0) ? 0 : term.col - 1;
+ if (direction < 0) {
+ for (; *y > 0; *y += direction) {
+ if (!(term.line[*y-1][term.col-1].mode
+ & ATTR_WRAP)) {
+ break;
+ }
+ }
+ } else if (direction > 0) {
+ for (; *y < term.row-1; *y += direction) {
+ if (!(term.line[*y][term.col-1].mode
+ & ATTR_WRAP)) {
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+void
+getbuttoninfo(void)
+{
+ int type;
+ uint state = wl.xkb.mods & ~forceselmod;
+
+ sel.alt = IS_SET(MODE_ALTSCREEN);
+
+ sel.oe.x = x2col(wl.px);
+ sel.oe.y = y2row(wl.py);
+ selnormalize();
+
+ sel.type = SEL_REGULAR;
+ for (type = 1; type < LEN(selmasks); ++type) {
+ if (match(selmasks[type], state)) {
+ sel.type = type;
+ break;
+ }
+ }
+}
+
+void
+wlmousereport(int button, bool release, int x, int y)
+{
+ int len;
+ char buf[40];
+
+ if (!IS_SET(MODE_MOUSEX10)) {
+ button += ((wl.xkb.mods & MOD_MASK_SHIFT) ? 4 : 0)
+ + ((wl.xkb.mods & MOD_MASK_LOGO ) ? 8 : 0)
+ + ((wl.xkb.mods & MOD_MASK_CTRL ) ? 16 : 0);
+ }
+
+ if (IS_SET(MODE_MOUSESGR)) {
+ len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
+ button, x+1, y+1, release ? 'm' : 'M');
+ } else if (x < 223 && y < 223) {
+ len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
+ 32+button, 32+x+1, 32+y+1);
+ } else {
+ return;
+ }
+
+ ttywrite(buf, len);
+}
+
+void
+wlmousereportbutton(uint32_t button, uint32_t state)
+{
+ bool release = state == WL_POINTER_BUTTON_STATE_RELEASED;
+
+ if (!IS_SET(MODE_MOUSESGR) && release) {
+ button = 3;
+ } else {
+ switch (button) {
+ case BTN_LEFT:
+ button = 0;
+ break;
+ case BTN_MIDDLE:
+ button = 1;
+ break;
+ case BTN_RIGHT:
+ button = 2;
+ break;
+ }
+ }
+
+ oldbutton = release ? 3 : button;
+
+ /* don't report release events when in X10 mode */
+ if (IS_SET(MODE_MOUSEX10) && release) {
+ return;
+ }
+
+ wlmousereport(button, release, oldx, oldy);
+}
+
+void
+wlmousereportmotion(wl_fixed_t fx, wl_fixed_t fy)
+{
+ int x = x2col(wl_fixed_to_int(fx)), y = y2row(wl_fixed_to_int(fy));
+
+ if (x == oldx && y == oldy)
+ return;
+ if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
+ return;
+ /* MOUSE_MOTION: no reporting if no button is pressed */
+ if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+ return;
+
+ oldx = x;
+ oldy = y;
+ wlmousereport(oldbutton + 32, false, x, y);
+}
+
+void
+wlmousereportaxis(uint32_t axis, wl_fixed_t amount)
+{
+ wlmousereport(64 + (axis == AXIS_VERTICAL ? 4 : 6)
+ + (amount > 0 ? 1 : 0), false, oldx, oldy);
+}
+
+char *
+getsel(void)
+{
+ char *str, *ptr;
+ int y, bufsize, lastx, linelen;
+ Glyph *gp, *last;
+
+ if (sel.ob.x == -1)
+ return NULL;
+
+ bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
+ ptr = str = xmalloc(bufsize);
+
+ /* append every set & selected glyph to the selection */
+ for (y = sel.nb.y; y <= sel.ne.y; y++) {
+ linelen = tlinelen(y);
+
+ if (sel.type == SEL_RECTANGULAR) {
+ gp = &term.line[y][sel.nb.x];
+ lastx = sel.ne.x;
+ } else {
+ gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
+ lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
+ }
+ last = &term.line[y][MIN(lastx, linelen-1)];
+ while (last >= gp && last->u == ' ')
+ --last;
+
+ for ( ; gp <= last; ++gp) {
+ if (gp->mode & ATTR_WDUMMY)
+ continue;
+
+ ptr += utf8encode(gp->u, ptr);
+ }
+
+ /*
+ * Copy and pasting of line endings is inconsistent
+ * in the inconsistent terminal and GUI world.
+ * The best solution seems like to produce '\n' when
+ * something is copied from st and convert '\n' to
+ * '\r', when something to be pasted is received by
+ * st.
+ * FIXME: Fix the computer world.
+ */
+ if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
+ *ptr++ = '\n';
+ }
+ *ptr = 0;
+ return str;
+}
+
+void
+selcopy(uint32_t serial)
+{
+ wlsetsel(getsel(), serial);
+}
+
+static inline void
+selwritebuf(char *buf, int len)
+{
+ char *repl = buf;
+
+ /*
+ * As seen in getsel:
+ * Line endings are inconsistent in the terminal and GUI world
+ * copy and pasting. When receiving some selection data,
+ * replace all '\n' with '\r'.
+ * FIXME: Fix the computer world.
+ */
+ while ((repl = memchr(repl, '\n', len))) {
+ *repl++ = '\r';
+ }
+
+ if (IS_SET(MODE_BRCKTPASTE))
+ ttywrite("\033[200~", 6);
+ ttysend(buf, len);
+ if (IS_SET(MODE_BRCKTPASTE))
+ ttywrite("\033[201~", 6);
+}
+
+void
+selpaste(const Arg *dummy)
+{
+ int fds[2], len, left;
+ char buf[BUFSIZ], *str;
+
+ if (wl.seloffer) {
+ /* check if we are pasting from ourselves */
+ if (sel.source) {
+ str = sel.primary;
+ left = strlen(sel.primary);
+ while (left > 0) {
+ len = MIN(sizeof buf, left);
+ memcpy(buf, str, len);
+ selwritebuf(buf, len);
+ left -= len;
+ str += len;
+ }
+ } else {
+ pipe(fds);
+ wl_data_offer_receive(wl.seloffer, "text/plain", fds[1]);
+ wl_display_flush(wl.dpy);
+ close(fds[1]);
+ while ((len = read(fds[0], buf, sizeof buf)) > 0) {
+ selwritebuf(buf, len);
+ }
+ close(fds[0]);
+ }
+ }
+}
+
+void
+selclear(void)
+{
+ if (sel.ob.x == -1)
+ return;
+ sel.mode = SEL_IDLE;
+ sel.ob.x = -1;
+ tsetdirt(sel.nb.y, sel.ne.y);
+}
+
+void
+wlsetsel(char *str, uint32_t serial)
+{
+ free(sel.primary);
+ sel.primary = str;
+
+ if (str) {
+ sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager);
+ wl_data_source_add_listener(sel.source, &datasrclistener, NULL);
+ wl_data_source_offer(sel.source, "text/plain; charset=utf-8");
+ } else {
+ sel.source = NULL;
+ }
+ wl_data_device_set_selection(wl.datadev, sel.source, serial);
+}
+
+void
+die(const char *errstr, ...)
+{
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void
+execsh(void)
+{
+ char **args, *sh, *prog;
+ const struct passwd *pw;
+
+ errno = 0;
+ if ((pw = getpwuid(getuid())) == NULL) {
+ if (errno)
+ die("getpwuid:%s\n", strerror(errno));
+ else
+ die("who are you?\n");
+ }
+
+ if ((sh = getenv("SHELL")) == NULL)
+ sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
+
+ if (opt_cmd)
+ prog = opt_cmd[0];
+ else if (utmp)
+ prog = utmp;
+ else
+ prog = sh;
+ args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL};
+
+ unsetenv("COLUMNS");
+ unsetenv("LINES");
+ unsetenv("TERMCAP");
+ setenv("LOGNAME", pw->pw_name, 1);
+ setenv("USER", pw->pw_name, 1);
+ setenv("SHELL", sh, 1);
+ setenv("HOME", pw->pw_dir, 1);
+ setenv("TERM", termname, 1);
+
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGALRM, SIG_DFL);
+
+ execvp(prog, args);
+ _exit(1);
+}
+
+void
+sigchld(int a)
+{
+ int stat;
+ pid_t p;
+
+ if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
+ die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
+
+ if (pid != p)
+ return;
+
+ if (!WIFEXITED(stat) || WEXITSTATUS(stat))
+ die("child finished with error '%d'\n", stat);
+ exit(0);
+}
+
+
+void
+stty(void)
+{
+ char cmd[_POSIX_ARG_MAX], **p, *q, *s;
+ size_t n, siz;
+
+ if ((n = strlen(stty_args)) > sizeof(cmd)-1)
+ die("incorrect stty parameters\n");
+ memcpy(cmd, stty_args, n);
+ q = cmd + n;
+ siz = sizeof(cmd) - n;
+ for (p = opt_cmd; p && (s = *p); ++p) {
+ if ((n = strlen(s)) > siz-1)
+ die("stty parameter length too long\n");
+ *q++ = ' ';
+ q = memcpy(q, s, n);
+ q += n;
+ siz-= n + 1;
+ }
+ *q = '\0';
+ if (system(cmd) != 0)
+ perror("Couldn't call stty");
+}
+
+void
+ttynew(void)
+{
+ int m, s;
+ struct winsize w = {term.row, term.col, 0, 0};
+
+ if (opt_io) {
+ term.mode |= MODE_PRINT;
+ iofd = (!strcmp(opt_io, "-")) ?
+ 1 : open(opt_io, O_WRONLY | O_CREAT, 0666);
+ if (iofd < 0) {
+ fprintf(stderr, "Error opening %s:%s\n",
+ opt_io, strerror(errno));
+ }
+ }
+
+ if (opt_line) {
+ if ((cmdfd = open(opt_line, O_RDWR)) < 0)
+ die("open line failed: %s\n", strerror(errno));
+ close(0);
+ dup(cmdfd);
+ stty();
+ return;
+ }
+
+ /* seems to work fine on linux, openbsd and freebsd */
+ if (openpty(&m, &s, NULL, NULL, &w) < 0)
+ die("openpty failed: %s\n", strerror(errno));
+
+ switch (pid = fork()) {
+ case -1:
+ die("fork failed\n");
+ break;
+ case 0:
+ close(iofd);
+ setsid(); /* create a new process group */
+ dup2(s, 0);
+ dup2(s, 1);
+ dup2(s, 2);
+ if (ioctl(s, TIOCSCTTY, NULL) < 0)
+ die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
+ close(s);
+ close(m);
+ execsh();
+ break;
+ default:
+ close(s);
+ cmdfd = m;
+ signal(SIGCHLD, sigchld);
+ break;
+ }
+}
+
+void
+ttyread(void)
+{
+ static char buf[BUFSIZ];
+ static int buflen = 0;
+ char *ptr;
+ int charsize; /* size of utf8 char in bytes */
+ Rune unicodep;
+ int ret;
+
+ /* append read bytes to unprocessed bytes */
+ if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
+ die("Couldn't read from shell: %s\n", strerror(errno));
+
+ /* process every complete utf8 char */
+ buflen += ret;
+ ptr = buf;
+ while ((charsize = utf8decode(ptr, &unicodep, buflen))) {
+ tputc(unicodep);
+ ptr += charsize;
+ buflen -= charsize;
+ }
+
+ /* keep any uncomplete utf8 char for the next call */
+ memmove(buf, ptr, buflen);
+ needdraw = true;
+}
+
+void
+ttywrite(const char *s, size_t n)
+{
+ fd_set wfd;
+ struct timespec tv;
+ ssize_t r;
+
+ /*
+ * Remember that we are using a pty, which might be a modem line.
+ * Writing too much will clog the line. That's why we are doing this
+ * dance.
+ * FIXME: Migrate the world to Plan 9.
+ */
+ while (n > 0) {
+ FD_ZERO(&wfd);
+ FD_SET(cmdfd, &wfd);
+ tv.tv_sec = 0;
+ tv.tv_nsec = 0;
+
+ /* Check if we can write. */
+ if (pselect(cmdfd+1, NULL, &wfd, NULL, &tv, NULL) < 0) {
+ if (errno == EINTR)
+ continue;
+ die("select failed: %s\n", strerror(errno));
+ }
+ if(!FD_ISSET(cmdfd, &wfd)) {
+ /* No, then free some buffer space. */
+ ttyread();
+ } else {
+ /*
+ * Only write 256 bytes at maximum. This seems to be a
+ * reasonable value for a serial line. Bigger values
+ * might clog the I/O.
+ */
+ r = write(cmdfd, s, (n < 256)? n : 256);
+ if (r < 0) {
+ die("write error on tty: %s\n",
+ strerror(errno));
+ }
+ if (r < n) {
+ /*
+ * We weren't able to write out everything.
+ * This means the buffer is getting full
+ * again. Empty it.
+ */
+ ttyread();
+ n -= r;
+ s += r;
+ } else {
+ /* All bytes have been written. */
+ break;
+ }
+ }
+ }
+}
+
+void
+ttysend(char *s, size_t n)
+{
+ int len;
+ Rune u;
+
+ ttywrite(s, n);
+ if (IS_SET(MODE_ECHO))
+ while ((len = utf8decode(s, &u, n)) > 0) {
+ techo(u);
+ n -= len;
+ s += len;
+ }
+}
+
+void
+ttyresize(void)
+{
+ struct winsize w;
+
+ w.ws_row = term.row;
+ w.ws_col = term.col;
+ w.ws_xpixel = wl.tw;
+ w.ws_ypixel = wl.th;
+ if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
+ fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
+}
+
+int
+tattrset(int attr)
+{
+ int i, j;
+
+ for (i = 0; i < term.row-1; i++) {
+ for (j = 0; j < term.col-1; j++) {
+ if (term.line[i][j].mode & attr)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void
+tsetdirt(int top, int bot)
+{
+ int i;
+
+ LIMIT(top, 0, term.row-1);
+ LIMIT(bot, 0, term.row-1);
+
+ for (i = top; i <= bot; i++)
+ term.dirty[i] = 1;
+
+ needdraw = true;
+}
+
+void
+tsetdirtattr(int attr)
+{
+ int i, j;
+
+ for (i = 0; i < term.row-1; i++) {
+ for (j = 0; j < term.col-1; j++) {
+ if (term.line[i][j].mode & attr) {
+ tsetdirt(i, i);
+ break;
+ }
+ }
+ }
+}
+
+void
+tfulldirt(void)
+{
+ tsetdirt(0, term.row-1);
+}
+
+void
+tcursor(int mode)
+{
+ static TCursor c[2];
+ int alt = IS_SET(MODE_ALTSCREEN);
+
+ if (mode == CURSOR_SAVE) {
+ c[alt] = term.c;
+ } else if (mode == CURSOR_LOAD) {
+ term.c = c[alt];
+ tmoveto(c[alt].x, c[alt].y);
+ }
+}
+
+void
+treset(void)
+{
+ uint i;
+
+ term.c = (TCursor){{
+ .mode = ATTR_NULL,
+ .fg = defaultfg,
+ .bg = defaultbg
+ }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
+
+ memset(term.tabs, 0, term.col * sizeof(*term.tabs));
+ for (i = tabspaces; i < term.col; i += tabspaces)
+ term.tabs[i] = 1;
+ term.top = 0;
+ term.bot = term.row - 1;
+ term.mode = MODE_WRAP;
+ memset(term.trantbl, CS_USA, sizeof(term.trantbl));
+ term.charset = 0;
+
+ for (i = 0; i < 2; i++) {
+ tmoveto(0, 0);
+ tcursor(CURSOR_SAVE);
+ tclearregion(0, 0, term.col-1, term.row-1);
+ tswapscreen();
+ }
+}
+
+void
+tnew(int col, int row)
+{
+ term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
+ tresize(col, row);
+ term.numlock = 1;
+
+ treset();
+}
+
+void
+tswapscreen(void)
+{
+ Line *tmp = term.line;
+
+ term.line = term.alt;
+ term.alt = tmp;
+ term.mode ^= MODE_ALTSCREEN;
+ tfulldirt();
+}
+
+void
+tscrolldown(int orig, int n)
+{
+ int i;
+ Line temp;
+
+ LIMIT(n, 0, term.bot-orig+1);
+
+ tsetdirt(orig, term.bot-n);
+ tclearregion(0, term.bot-n+1, term.col-1, term.bot);
+
+ for (i = term.bot; i >= orig+n; i--) {
+ temp = term.line[i];
+ term.line[i] = term.line[i-n];
+ term.line[i-n] = temp;
+ }
+
+ selscroll(orig, n);
+}
+
+void
+tscrollup(int orig, int n)
+{
+ int i;
+ Line temp;
+
+ LIMIT(n, 0, term.bot-orig+1);
+
+ tclearregion(0, orig, term.col-1, orig+n-1);
+ tsetdirt(orig+n, term.bot);
+
+ for (i = orig; i <= term.bot-n; i++) {
+ temp = term.line[i];
+ term.line[i] = term.line[i+n];
+ term.line[i+n] = temp;
+ }
+
+ selscroll(orig, -n);
+}
+
+void
+selscroll(int orig, int n)
+{
+ if (sel.ob.x == -1)
+ return;
+
+ if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
+ if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
+ selclear();
+ return;
+ }
+ if (sel.type == SEL_RECTANGULAR) {
+ if (sel.ob.y < term.top)
+ sel.ob.y = term.top;
+ if (sel.oe.y > term.bot)
+ sel.oe.y = term.bot;
+ } else {
+ if (sel.ob.y < term.top) {
+ sel.ob.y = term.top;
+ sel.ob.x = 0;
+ }
+ if (sel.oe.y > term.bot) {
+ sel.oe.y = term.bot;
+ sel.oe.x = term.col;
+ }
+ }
+ selnormalize();
+ }
+}
+
+void
+tnewline(int first_col)
+{
+ int y = term.c.y;
+
+ if (y == term.bot) {
+ tscrollup(term.top, 1);
+ } else {
+ y++;
+ }
+ tmoveto(first_col ? 0 : term.c.x, y);
+}
+
+void
+csiparse(void)
+{
+ char *p = csiescseq.buf, *np;
+ long int v;
+
+ csiescseq.narg = 0;
+ if (*p == '?') {
+ csiescseq.priv = 1;
+ p++;
+ }
+
+ csiescseq.buf[csiescseq.len] = '\0';
+ while (p < csiescseq.buf+csiescseq.len) {
+ np = NULL;
+ v = strtol(p, &np, 10);
+ if (np == p)
+ v = 0;
+ if (v == LONG_MAX || v == LONG_MIN)
+ v = -1;
+ csiescseq.arg[csiescseq.narg++] = v;
+ p = np;
+ if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+ break;
+ p++;
+ }
+ csiescseq.mode[0] = *p++;
+ csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0';
+}
+
+/* for absolute user moves, when decom is set */
+void
+tmoveato(int x, int y)
+{
+ tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0));
+}
+
+void
+tmoveto(int x, int y)
+{
+ int miny, maxy;
+
+ if (term.c.state & CURSOR_ORIGIN) {
+ miny = term.top;
+ maxy = term.bot;
+ } else {
+ miny = 0;
+ maxy = term.row - 1;
+ }
+ term.c.state &= ~CURSOR_WRAPNEXT;
+ term.c.x = LIMIT(x, 0, term.col-1);
+ term.c.y = LIMIT(y, miny, maxy);
+}
+
+void
+tsetchar(Rune u, Glyph *attr, int x, int y)
+{
+ static char *vt100_0[62] = { /* 0x41 - 0x7e */
+ "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */
+ 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */
+ "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */
+ "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */
+ "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
+ "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
+ };
+
+ /*
+ * The table is proudly stolen from rxvt.
+ */
+ if (term.trantbl[term.charset] == CS_GRAPHIC0 &&
+ BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
+ utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
+
+ if (term.line[y][x].mode & ATTR_WIDE) {
+ if (x+1 < term.col) {
+ term.line[y][x+1].u = ' ';
+ term.line[y][x+1].mode &= ~ATTR_WDUMMY;
+ }
+ } else if (term.line[y][x].mode & ATTR_WDUMMY) {
+ term.line[y][x-1].u = ' ';
+ term.line[y][x-1].mode &= ~ATTR_WIDE;
+ }
+
+ term.dirty[y] = 1;
+ term.line[y][x] = *attr;
+ term.line[y][x].u = u;
+}
+
+void
+tclearregion(int x1, int y1, int x2, int y2)
+{
+ int x, y, temp;
+ Glyph *gp;
+
+ if (x1 > x2)
+ temp = x1, x1 = x2, x2 = temp;
+ if (y1 > y2)
+ temp = y1, y1 = y2, y2 = temp;
+
+ LIMIT(x1, 0, term.col-1);
+ LIMIT(x2, 0, term.col-1);
+ LIMIT(y1, 0, term.row-1);
+ LIMIT(y2, 0, term.row-1);
+
+ for (y = y1; y <= y2; y++) {
+ term.dirty[y] = 1;
+ for (x = x1; x <= x2; x++) {
+ gp = &term.line[y][x];
+ if (selected(x, y))
+ selclear();
+ gp->fg = term.c.attr.fg;
+ gp->bg = term.c.attr.bg;
+ gp->mode = 0;
+ gp->u = ' ';
+ }
+ }
+}
+
+void
+tdeletechar(int n)
+{
+ int dst, src, size;
+ Glyph *line;
+
+ LIMIT(n, 0, term.col - term.c.x);
+
+ dst = term.c.x;
+ src = term.c.x + n;
+ size = term.col - src;
+ line = term.line[term.c.y];
+
+ memmove(&line[dst], &line[src], size * sizeof(Glyph));
+ tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
+}
+
+void
+tinsertblank(int n)
+{
+ int dst, src, size;
+ Glyph *line;
+
+ LIMIT(n, 0, term.col - term.c.x);
+
+ dst = term.c.x + n;
+ src = term.c.x;
+ size = term.col - dst;
+ line = term.line[term.c.y];
+
+ memmove(&line[dst], &line[src], size * sizeof(Glyph));
+ tclearregion(src, term.c.y, dst - 1, term.c.y);
+}
+
+void
+tinsertblankline(int n)
+{
+ if (BETWEEN(term.c.y, term.top, term.bot))
+ tscrolldown(term.c.y, n);
+}
+
+void
+tdeleteline(int n)
+{
+ if (BETWEEN(term.c.y, term.top, term.bot))
+ tscrollup(term.c.y, n);
+}
+
+uint32_t
+tdefcolor(int *attr, int *npar, int l)
+{
+ int32_t idx = -1;
+ uint r, g, b;
+
+ switch (attr[*npar + 1]) {
+ case 2: /* direct color in RGB space */
+ if (*npar + 4 >= l) {
+ fprintf(stderr,
+ "erresc(38): Incorrect number of parameters (%d)\n",
+ *npar);
+ break;
+ }
+ r = attr[*npar + 2];
+ g = attr[*npar + 3];
+ b = attr[*npar + 4];
+ *npar += 4;
+ if (!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255))
+ fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n",
+ r, g, b);
+ else
+ idx = TRUECOLOR(r, g, b);
+ break;
+ case 5: /* indexed color */
+ if (*npar + 2 >= l) {
+ fprintf(stderr,
+ "erresc(38): Incorrect number of parameters (%d)\n",
+ *npar);
+ break;
+ }
+ *npar += 2;
+ if (!BETWEEN(attr[*npar], 0, 255))
+ fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]);
+ else
+ idx = attr[*npar];
+ break;
+ case 0: /* implemented defined (only foreground) */
+ case 1: /* transparent */
+ case 3: /* direct color in CMY space */
+ case 4: /* direct color in CMYK space */
+ default:
+ fprintf(stderr,
+ "erresc(38): gfx attr %d unknown\n", attr[*npar]);
+ break;
+ }
+
+ return idx;
+}
+
+void
+tsetattr(int *attr, int l)
+{
+ int i;
+ uint32_t idx;
+
+ for (i = 0; i < l; i++) {
+ switch (attr[i]) {
+ case 0:
+ term.c.attr.mode &= ~(
+ ATTR_BOLD |
+ ATTR_FAINT |
+ ATTR_ITALIC |
+ ATTR_UNDERLINE |
+ ATTR_BLINK |
+ ATTR_REVERSE |
+ ATTR_INVISIBLE |
+ ATTR_STRUCK );
+ term.c.attr.fg = defaultfg;
+ term.c.attr.bg = defaultbg;
+ break;
+ case 1:
+ term.c.attr.mode |= ATTR_BOLD;
+ break;
+ case 2:
+ term.c.attr.mode |= ATTR_FAINT;
+ break;
+ case 3:
+ term.c.attr.mode |= ATTR_ITALIC;
+ break;
+ case 4:
+ term.c.attr.mode |= ATTR_UNDERLINE;
+ break;
+ case 5: /* slow blink */
+ /* FALLTHROUGH */
+ case 6: /* rapid blink */
+ term.c.attr.mode |= ATTR_BLINK;
+ break;
+ case 7:
+ term.c.attr.mode |= ATTR_REVERSE;
+ break;
+ case 8:
+ term.c.attr.mode |= ATTR_INVISIBLE;
+ break;
+ case 9:
+ term.c.attr.mode |= ATTR_STRUCK;
+ break;
+ case 22:
+ term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
+ break;
+ case 23:
+ term.c.attr.mode &= ~ATTR_ITALIC;
+ break;
+ case 24:
+ term.c.attr.mode &= ~ATTR_UNDERLINE;
+ break;
+ case 25:
+ term.c.attr.mode &= ~ATTR_BLINK;
+ break;
+ case 27:
+ term.c.attr.mode &= ~ATTR_REVERSE;
+ break;
+ case 28:
+ term.c.attr.mode &= ~ATTR_INVISIBLE;
+ break;
+ case 29:
+ term.c.attr.mode &= ~ATTR_STRUCK;
+ break;
+ case 38:
+ if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ term.c.attr.fg = idx;
+ break;
+ case 39:
+ term.c.attr.fg = defaultfg;
+ break;
+ case 48:
+ if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ term.c.attr.bg = idx;
+ break;
+ case 49:
+ term.c.attr.bg = defaultbg;
+ break;
+ default:
+ if (BETWEEN(attr[i], 30, 37)) {
+ term.c.attr.fg = attr[i] - 30;
+ } else if (BETWEEN(attr[i], 40, 47)) {
+ term.c.attr.bg = attr[i] - 40;
+ } else if (BETWEEN(attr[i], 90, 97)) {
+ term.c.attr.fg = attr[i] - 90 + 8;
+ } else if (BETWEEN(attr[i], 100, 107)) {
+ term.c.attr.bg = attr[i] - 100 + 8;
+ } else {
+ fprintf(stderr,
+ "erresc(default): gfx attr %d unknown\n",
+ attr[i]), csidump();
+ }
+ break;
+ }
+ }
+}
+
+void
+tsetscroll(int t, int b)
+{
+ int temp;
+
+ LIMIT(t, 0, term.row-1);
+ LIMIT(b, 0, term.row-1);
+ if (t > b) {
+ temp = t;
+ t = b;
+ b = temp;
+ }
+ term.top = t;
+ term.bot = b;
+}
+
+void
+tsetmode(int priv, int set, int *args, int narg)
+{
+ int *lim, mode;
+ int alt;
+
+ for (lim = args + narg; args < lim; ++args) {
+ if (priv) {
+ switch (*args) {
+ case 1: /* DECCKM -- Cursor key */
+ MODBIT(term.mode, set, MODE_APPCURSOR);
+ break;
+ case 5: /* DECSCNM -- Reverse video */
+ mode = term.mode;
+ MODBIT(term.mode, set, MODE_REVERSE);
+ if (mode != term.mode)
+ redraw();
+ break;
+ case 6: /* DECOM -- Origin */
+ MODBIT(term.c.state, set, CURSOR_ORIGIN);
+ tmoveato(0, 0);
+ break;
+ case 7: /* DECAWM -- Auto wrap */
+ MODBIT(term.mode, set, MODE_WRAP);
+ break;
+ case 0: /* Error (IGNORED) */
+ case 2: /* DECANM -- ANSI/VT52 (IGNORED) */
+ case 3: /* DECCOLM -- Column (IGNORED) */
+ case 4: /* DECSCLM -- Scroll (IGNORED) */
+ case 8: /* DECARM -- Auto repeat (IGNORED) */
+ case 18: /* DECPFF -- Printer feed (IGNORED) */
+ case 19: /* DECPEX -- Printer extent (IGNORED) */
+ case 42: /* DECNRCM -- National characters (IGNORED) */
+ case 12: /* att610 -- Start blinking cursor (IGNORED) */
+ break;
+ case 25: /* DECTCEM -- Text Cursor Enable Mode */
+ MODBIT(term.mode, !set, MODE_HIDE);
+ break;
+ case 9: /* X10 mouse compatibility mode */
+ MODBIT(term.mode, 0, MODE_MOUSE);
+ MODBIT(term.mode, set, MODE_MOUSEX10);
+ break;
+ case 1000: /* 1000: report button press */
+ MODBIT(term.mode, 0, MODE_MOUSE);
+ MODBIT(term.mode, set, MODE_MOUSEBTN);
+ break;
+ case 1002: /* 1002: report motion on button press */
+ MODBIT(term.mode, 0, MODE_MOUSE);
+ MODBIT(term.mode, set, MODE_MOUSEMOTION);
+ break;
+ case 1003: /* 1003: enable all mouse motions */
+ MODBIT(term.mode, 0, MODE_MOUSE);
+ MODBIT(term.mode, set, MODE_MOUSEMANY);
+ break;
+ case 1004: /* 1004: send focus events to tty */
+ MODBIT(term.mode, set, MODE_FOCUS);
+ break;
+ case 1006: /* 1006: extended reporting mode */
+ MODBIT(term.mode, set, MODE_MOUSESGR);
+ break;
+ case 1034:
+ MODBIT(term.mode, set, MODE_8BIT);
+ break;
+ case 1049: /* swap screen & set/restore cursor as xterm */
+ if (!allowaltscreen)
+ break;
+ tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+ /* FALLTHROUGH */
+ case 47: /* swap screen */
+ case 1047:
+ if (!allowaltscreen)
+ break;
+ alt = IS_SET(MODE_ALTSCREEN);
+ if (alt) {
+ tclearregion(0, 0, term.col-1,
+ term.row-1);
+ }
+ if (set ^ alt) /* set is always 1 or 0 */
+ tswapscreen();
+ if (*args != 1049)
+ break;
+ /* FALLTHROUGH */
+ case 1048:
+ tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+ break;
+ case 2004: /* 2004: bracketed paste mode */
+ MODBIT(term.mode, set, MODE_BRCKTPASTE);
+ break;
+ /* Not implemented mouse modes. See comments there. */
+ case 1001: /* mouse highlight mode; can hang the
+ terminal by design when implemented. */
+ case 1005: /* UTF-8 mouse mode; will confuse
+ applications not supporting UTF-8
+ and luit. */
+ case 1015: /* urxvt mangled mouse mode; incompatible
+ and can be mistaken for other control
+ codes. */
+ default:
+ fprintf(stderr,
+ "erresc: unknown private set/reset mode %d\n",
+ *args);
+ break;
+ }
+ } else {
+ switch (*args) {
+ case 0: /* Error (IGNORED) */
+ break;
+ case 2: /* KAM -- keyboard action */
+ MODBIT(term.mode, set, MODE_KBDLOCK);
+ break;
+ case 4: /* IRM -- Insertion-replacement */
+ MODBIT(term.mode, set, MODE_INSERT);
+ break;
+ case 12: /* SRM -- Send/Receive */
+ MODBIT(term.mode, !set, MODE_ECHO);
+ break;
+ case 20: /* LNM -- Linefeed/new line */
+ MODBIT(term.mode, set, MODE_CRLF);
+ break;
+ default:
+ fprintf(stderr,
+ "erresc: unknown set/reset mode %d\n",
+ *args);
+ break;
+ }
+ }
+ }
+}
+
+void
+csihandle(void)
+{
+ char buf[40];
+ int len;
+
+ switch (csiescseq.mode[0]) {
+ default:
+ unknown:
+ fprintf(stderr, "erresc: unknown csi ");
+ csidump();
+ /* die(""); */
+ break;
+ case '@': /* ICH -- Insert <n> blank char */
+ DEFAULT(csiescseq.arg[0], 1);
+ tinsertblank(csiescseq.arg[0]);
+ break;
+ case 'A': /* CUU -- Cursor <n> Up */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(term.c.x, term.c.y-csiescseq.arg[0]);
+ break;
+ case 'B': /* CUD -- Cursor <n> Down */
+ case 'e': /* VPR --Cursor <n> Down */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(term.c.x, term.c.y+csiescseq.arg[0]);
+ break;
+ case 'i': /* MC -- Media Copy */
+ switch (csiescseq.arg[0]) {
+ case 0:
+ tdump();
+ break;
+ case 1:
+ tdumpline(term.c.y);
+ break;
+ case 2:
+ tdumpsel();
+ break;
+ case 4:
+ term.mode &= ~MODE_PRINT;
+ break;
+ case 5:
+ term.mode |= MODE_PRINT;
+ break;
+ }
+ break;
+ case 'c': /* DA -- Device Attributes */
+ if (csiescseq.arg[0] == 0)
+ ttywrite(vtiden, sizeof(vtiden) - 1);
+ break;
+ case 'C': /* CUF -- Cursor <n> Forward */
+ case 'a': /* HPR -- Cursor <n> Forward */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(term.c.x+csiescseq.arg[0], term.c.y);
+ break;
+ case 'D': /* CUB -- Cursor <n> Backward */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(term.c.x-csiescseq.arg[0], term.c.y);
+ break;
+ case 'E': /* CNL -- Cursor <n> Down and first col */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(0, term.c.y+csiescseq.arg[0]);
+ break;
+ case 'F': /* CPL -- Cursor <n> Up and first col */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(0, term.c.y-csiescseq.arg[0]);
+ break;
+ case 'g': /* TBC -- Tabulation clear */
+ switch (csiescseq.arg[0]) {
+ case 0: /* clear current tab stop */
+ term.tabs[term.c.x] = 0;
+ break;
+ case 3: /* clear all the tabs */
+ memset(term.tabs, 0, term.col * sizeof(*term.tabs));
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ case 'G': /* CHA -- Move to <col> */
+ case '`': /* HPA */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveto(csiescseq.arg[0]-1, term.c.y);
+ break;
+ case 'H': /* CUP -- Move to <row> <col> */
+ case 'f': /* HVP */
+ DEFAULT(csiescseq.arg[0], 1);
+ DEFAULT(csiescseq.arg[1], 1);
+ tmoveato(csiescseq.arg[1]-1, csiescseq.arg[0]-1);
+ break;
+ case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
+ DEFAULT(csiescseq.arg[0], 1);
+ tputtab(csiescseq.arg[0]);
+ break;
+ case 'J': /* ED -- Clear screen */
+ selclear();
+ switch (csiescseq.arg[0]) {
+ case 0: /* below */
+ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
+ if (term.c.y < term.row-1) {
+ tclearregion(0, term.c.y+1, term.col-1,
+ term.row-1);
+ }
+ break;
+ case 1: /* above */
+ if (term.c.y > 1)
+ tclearregion(0, 0, term.col-1, term.c.y-1);
+ tclearregion(0, term.c.y, term.c.x, term.c.y);
+ break;
+ case 2: /* all */
+ tclearregion(0, 0, term.col-1, term.row-1);
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ case 'K': /* EL -- Clear line */
+ switch (csiescseq.arg[0]) {
+ case 0: /* right */
+ tclearregion(term.c.x, term.c.y, term.col-1,
+ term.c.y);
+ break;
+ case 1: /* left */
+ tclearregion(0, term.c.y, term.c.x, term.c.y);
+ break;
+ case 2: /* all */
+ tclearregion(0, term.c.y, term.col-1, term.c.y);
+ break;
+ }
+ break;
+ case 'S': /* SU -- Scroll <n> line up */
+ DEFAULT(csiescseq.arg[0], 1);
+ tscrollup(term.top, csiescseq.arg[0]);
+ break;
+ case 'T': /* SD -- Scroll <n> line down */
+ DEFAULT(csiescseq.arg[0], 1);
+ tscrolldown(term.top, csiescseq.arg[0]);
+ break;
+ case 'L': /* IL -- Insert <n> blank lines */
+ DEFAULT(csiescseq.arg[0], 1);
+ tinsertblankline(csiescseq.arg[0]);
+ break;
+ case 'l': /* RM -- Reset Mode */
+ tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg);
+ break;
+ case 'M': /* DL -- Delete <n> lines */
+ DEFAULT(csiescseq.arg[0], 1);
+ tdeleteline(csiescseq.arg[0]);
+ break;
+ case 'X': /* ECH -- Erase <n> char */
+ DEFAULT(csiescseq.arg[0], 1);
+ tclearregion(term.c.x, term.c.y,
+ term.c.x + csiescseq.arg[0] - 1, term.c.y);
+ break;
+ case 'P': /* DCH -- Delete <n> char */
+ DEFAULT(csiescseq.arg[0], 1);
+ tdeletechar(csiescseq.arg[0]);
+ break;
+ case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
+ DEFAULT(csiescseq.arg[0], 1);
+ tputtab(-csiescseq.arg[0]);
+ break;
+ case 'd': /* VPA -- Move to <row> */
+ DEFAULT(csiescseq.arg[0], 1);
+ tmoveato(term.c.x, csiescseq.arg[0]-1);
+ break;
+ case 'h': /* SM -- Set terminal mode */
+ tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg);
+ break;
+ case 'm': /* SGR -- Terminal attribute (color) */
+ tsetattr(csiescseq.arg, csiescseq.narg);
+ break;
+ case 'n': /* DSR – Device Status Report (cursor position) */
+ if (csiescseq.arg[0] == 6) {
+ len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
+ term.c.y+1, term.c.x+1);
+ ttywrite(buf, len);
+ }
+ break;
+ case 'r': /* DECSTBM -- Set Scrolling Region */
+ if (csiescseq.priv) {
+ goto unknown;
+ } else {
+ DEFAULT(csiescseq.arg[0], 1);
+ DEFAULT(csiescseq.arg[1], term.row);
+ tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1);
+ tmoveato(0, 0);
+ }
+ break;
+ case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
+ tcursor(CURSOR_SAVE);
+ break;
+ case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
+ tcursor(CURSOR_LOAD);
+ break;
+ case ' ':
+ switch (csiescseq.mode[1]) {
+ case 'q': /* DECSCUSR -- Set Cursor Style */
+ DEFAULT(csiescseq.arg[0], 1);
+ if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
+ goto unknown;
+ }
+ wl.cursor = csiescseq.arg[0];
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ }
+}
+
+void
+csidump(void)
+{
+ int i;
+ uint c;
+
+ printf("ESC[");
+ for (i = 0; i < csiescseq.len; i++) {
+ c = csiescseq.buf[i] & 0xff;
+ if (isprint(c)) {
+ putchar(c);
+ } else if (c == '\n') {
+ printf("(\\n)");
+ } else if (c == '\r') {
+ printf("(\\r)");
+ } else if (c == 0x1b) {
+ printf("(\\e)");
+ } else {
+ printf("(%02x)", c);
+ }
+ }
+ putchar('\n');
+}
+
+void
+csireset(void)
+{
+ memset(&csiescseq, 0, sizeof(csiescseq));
+}
+
+void
+strhandle(void)
+{
+ char *p = NULL;
+ int j, narg, par;
+
+ term.esc &= ~(ESC_STR_END|ESC_STR);
+ strparse();
+ par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
+
+ switch (strescseq.type) {
+ case ']': /* OSC -- Operating System Command */
+ switch (par) {
+ case 0:
+ case 1:
+ case 2:
+ if (narg > 1)
+ wlsettitle(strescseq.args[1]);
+ return;
+ case 4: /* color set */
+ if (narg < 3)
+ break;
+ p = strescseq.args[2];
+ /* FALLTHROUGH */
+ case 104: /* color reset, here p = NULL */
+ j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
+ if (wlsetcolorname(j, p)) {
+ fprintf(stderr, "erresc: invalid color %s\n", p);
+ } else {
+ /*
+ * TODO if defaultbg color is changed, borders
+ * are dirty
+ */
+ redraw();
+ }
+ return;
+ }
+ break;
+ case 'k': /* old title set compatibility */
+ wlsettitle(strescseq.args[0]);
+ return;
+ case 'P': /* DCS -- Device Control String */
+ case '_': /* APC -- Application Program Command */
+ case '^': /* PM -- Privacy Message */
+ return;
+ }
+
+ fprintf(stderr, "erresc: unknown str ");
+ strdump();
+}
+
+void
+strparse(void)
+{
+ int c;
+ char *p = strescseq.buf;
+
+ strescseq.narg = 0;
+ strescseq.buf[strescseq.len] = '\0';
+
+ if (*p == '\0')
+ return;
+
+ while (strescseq.narg < STR_ARG_SIZ) {
+ strescseq.args[strescseq.narg++] = p;
+ while ((c = *p) != ';' && c != '\0')
+ ++p;
+ if (c == '\0')
+ return;
+ *p++ = '\0';
+ }
+}
+
+void
+strdump(void)
+{
+ int i;
+ uint c;
+
+ printf("ESC%c", strescseq.type);
+ for (i = 0; i < strescseq.len; i++) {
+ c = strescseq.buf[i] & 0xff;
+ if (c == '\0') {
+ return;
+ } else if (isprint(c)) {
+ putchar(c);
+ } else if (c == '\n') {
+ printf("(\\n)");
+ } else if (c == '\r') {
+ printf("(\\r)");
+ } else if (c == 0x1b) {
+ printf("(\\e)");
+ } else {
+ printf("(%02x)", c);
+ }
+ }
+ printf("ESC\\\n");
+}
+
+void
+strreset(void)
+{
+ memset(&strescseq, 0, sizeof(strescseq));
+}
+
+void
+tprinter(char *s, size_t len)
+{
+ if (iofd != -1 && xwrite(iofd, s, len) < 0) {
+ fprintf(stderr, "Error writing in %s:%s\n",
+ opt_io, strerror(errno));
+ close(iofd);
+ iofd = -1;
+ }
+}
+
+void
+toggleprinter(const Arg *arg)
+{
+ term.mode ^= MODE_PRINT;
+}
+
+void
+printscreen(const Arg *arg)
+{
+ tdump();
+}
+
+void
+printsel(const Arg *arg)
+{
+ tdumpsel();
+}
+
+void
+tdumpsel(void)
+{
+ char *ptr;
+
+ if ((ptr = getsel())) {
+ tprinter(ptr, strlen(ptr));
+ free(ptr);
+ }
+}
+
+void
+tdumpline(int n)
+{
+ char buf[UTF_SIZ];
+ Glyph *bp, *end;
+
+ bp = &term.line[n][0];
+ end = &bp[MIN(tlinelen(n), term.col) - 1];
+ if (bp != end || bp->u != ' ') {
+ for ( ;bp <= end; ++bp)
+ tprinter(buf, utf8encode(bp->u, buf));
+ }
+ tprinter("\n", 1);
+}
+
+void
+tdump(void)
+{
+ int i;
+
+ for (i = 0; i < term.row; ++i)
+ tdumpline(i);
+}
+
+void
+tputtab(int n)
+{
+ uint x = term.c.x;
+
+ if (n > 0) {
+ while (x < term.col && n--)
+ for (++x; x < term.col && !term.tabs[x]; ++x)
+ /* nothing */ ;
+ } else if (n < 0) {
+ while (x > 0 && n++)
+ for (--x; x > 0 && !term.tabs[x]; --x)
+ /* nothing */ ;
+ }
+ term.c.x = LIMIT(x, 0, term.col-1);
+}
+
+void
+techo(Rune u)
+{
+ if (ISCONTROL(u)) { /* control code */
+ if (u & 0x80) {
+ u &= 0x7f;
+ tputc('^');
+ tputc('[');
+ } else if (u != '\n' && u != '\r' && u != '\t') {
+ u ^= 0x40;
+ tputc('^');
+ }
+ }
+ tputc(u);
+ needdraw = true;
+}
+
+void
+tdeftran(char ascii)
+{
+ static char cs[] = "0B";
+ static int vcs[] = {CS_GRAPHIC0, CS_USA};
+ char *p;
+
+ if ((p = strchr(cs, ascii)) == NULL) {
+ fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
+ } else {
+ term.trantbl[term.icharset] = vcs[p - cs];
+ }
+}
+
+void
+tdectest(char c)
+{
+ int x, y;
+
+ if (c == '8') { /* DEC screen alignment test. */
+ for (x = 0; x < term.col; ++x) {
+ for (y = 0; y < term.row; ++y)
+ tsetchar('E', &term.c.attr, x, y);
+ }
+ }
+}
+
+void
+tstrsequence(uchar c)
+{
+ switch (c) {
+ case 0x90: /* DCS -- Device Control String */
+ c = 'P';
+ break;
+ case 0x9f: /* APC -- Application Program Command */
+ c = '_';
+ break;
+ case 0x9e: /* PM -- Privacy Message */
+ c = '^';
+ break;
+ case 0x9d: /* OSC -- Operating System Command */
+ c = ']';
+ break;
+ }
+ strreset();
+ strescseq.type = c;
+ term.esc |= ESC_STR;
+}
+
+void
+tcontrolcode(uchar ascii)
+{
+ switch (ascii) {
+ case '\t': /* HT */
+ tputtab(1);
+ return;
+ case '\b': /* BS */
+ tmoveto(term.c.x-1, term.c.y);
+ return;
+ case '\r': /* CR */
+ tmoveto(0, term.c.y);
+ return;
+ case '\f': /* LF */
+ case '\v': /* VT */
+ case '\n': /* LF */
+ /* go to first col if the mode is set */
+ tnewline(IS_SET(MODE_CRLF));
+ return;
+ case '\a': /* BEL */
+ if (term.esc & ESC_STR_END) {
+ /* backwards compatibility to xterm */
+ strhandle();
+ } else {
+ if (!(wl.state & WIN_FOCUSED))
+ wlseturgency(1);
+ /* XXX: No bell on wayland
+ * if (bellvolume)
+ * XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
+ */
+ }
+ break;
+ case '\033': /* ESC */
+ csireset();
+ term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST);
+ term.esc |= ESC_START;
+ return;
+ case '\016': /* SO (LS1 -- Locking shift 1) */
+ case '\017': /* SI (LS0 -- Locking shift 0) */
+ term.charset = 1 - (ascii - '\016');
+ return;
+ case '\032': /* SUB */
+ tsetchar('?', &term.c.attr, term.c.x, term.c.y);
+ case '\030': /* CAN */
+ csireset();
+ break;
+ case '\005': /* ENQ (IGNORED) */
+ case '\000': /* NUL (IGNORED) */
+ case '\021': /* XON (IGNORED) */
+ case '\023': /* XOFF (IGNORED) */
+ case 0177: /* DEL (IGNORED) */
+ return;
+ case 0x84: /* TODO: IND */
+ break;
+ case 0x85: /* NEL -- Next line */
+ tnewline(1); /* always go to first col */
+ break;
+ case 0x88: /* HTS -- Horizontal tab stop */
+ term.tabs[term.c.x] = 1;
+ break;
+ case 0x8d: /* TODO: RI */
+ case 0x8e: /* TODO: SS2 */
+ case 0x8f: /* TODO: SS3 */
+ case 0x98: /* TODO: SOS */
+ break;
+ case 0x9a: /* DECID -- Identify Terminal */
+ ttywrite(vtiden, sizeof(vtiden) - 1);
+ break;
+ case 0x9b: /* TODO: CSI */
+ case 0x9c: /* TODO: ST */
+ break;
+ case 0x90: /* DCS -- Device Control String */
+ case 0x9f: /* APC -- Application Program Command */
+ case 0x9e: /* PM -- Privacy Message */
+ case 0x9d: /* OSC -- Operating System Command */
+ tstrsequence(ascii);
+ return;
+ }
+ /* only CAN, SUB, \a and C1 chars interrupt a sequence */
+ term.esc &= ~(ESC_STR_END|ESC_STR);
+}
+
+/*
+ * returns 1 when the sequence is finished and it hasn't to read
+ * more characters for this sequence, otherwise 0
+ */
+int
+eschandle(uchar ascii)
+{
+ switch (ascii) {
+ case '[':
+ term.esc |= ESC_CSI;
+ return 0;
+ case '#':
+ term.esc |= ESC_TEST;
+ return 0;
+ case 'P': /* DCS -- Device Control String */
+ case '_': /* APC -- Application Program Command */
+ case '^': /* PM -- Privacy Message */
+ case ']': /* OSC -- Operating System Command */
+ case 'k': /* old title set compatibility */
+ tstrsequence(ascii);
+ return 0;
+ case 'n': /* LS2 -- Locking shift 2 */
+ case 'o': /* LS3 -- Locking shift 3 */
+ term.charset = 2 + (ascii - 'n');
+ break;
+ case '(': /* GZD4 -- set primary charset G0 */
+ case ')': /* G1D4 -- set secondary charset G1 */
+ case '*': /* G2D4 -- set tertiary charset G2 */
+ case '+': /* G3D4 -- set quaternary charset G3 */
+ term.icharset = ascii - '(';
+ term.esc |= ESC_ALTCHARSET;
+ return 0;
+ case 'D': /* IND -- Linefeed */
+ if (term.c.y == term.bot) {
+ tscrollup(term.top, 1);
+ } else {
+ tmoveto(term.c.x, term.c.y+1);
+ }
+ break;
+ case 'E': /* NEL -- Next line */
+ tnewline(1); /* always go to first col */
+ break;
+ case 'H': /* HTS -- Horizontal tab stop */
+ term.tabs[term.c.x] = 1;
+ break;
+ case 'M': /* RI -- Reverse index */
+ if (term.c.y == term.top) {
+ tscrolldown(term.top, 1);
+ } else {
+ tmoveto(term.c.x, term.c.y-1);
+ }
+ break;
+ case 'Z': /* DECID -- Identify Terminal */
+ ttywrite(vtiden, sizeof(vtiden) - 1);
+ break;
+ case 'c': /* RIS -- Reset to inital state */
+ treset();
+ wlresettitle();
+ wlloadcols();
+ break;
+ case '=': /* DECPAM -- Application keypad */
+ term.mode |= MODE_APPKEYPAD;
+ break;
+ case '>': /* DECPNM -- Normal keypad */
+ term.mode &= ~MODE_APPKEYPAD;
+ break;
+ case '7': /* DECSC -- Save Cursor */
+ tcursor(CURSOR_SAVE);
+ break;
+ case '8': /* DECRC -- Restore Cursor */
+ tcursor(CURSOR_LOAD);
+ break;
+ case '\\': /* ST -- String Terminator */
+ if (term.esc & ESC_STR_END)
+ strhandle();
+ break;
+ default:
+ fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
+ (uchar) ascii, isprint(ascii)? ascii:'.');
+ break;
+ }
+ return 1;
+}
+
+void
+tputc(Rune u)
+{
+ char c[UTF_SIZ];
+ int control;
+ int width, len;
+ Glyph *gp;
+
+ control = ISCONTROL(u);
+ len = utf8encode(u, c);
+ if (!control && (width = wcwidth(u)) == -1) {
+ memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
+ width = 1;
+ }
+
+ if (IS_SET(MODE_PRINT))
+ tprinter(c, len);
+
+ /*
+ * STR sequence must be checked before anything else
+ * because it uses all following characters until it
+ * receives a ESC, a SUB, a ST or any other C1 control
+ * character.
+ */
+ if (term.esc & ESC_STR) {
+ if (u == '\a' || u == 030 || u == 032 || u == 033 ||
+ ISCONTROLC1(u)) {
+ term.esc &= ~(ESC_START|ESC_STR);
+ term.esc |= ESC_STR_END;
+ } else if (strescseq.len + len < sizeof(strescseq.buf) - 1) {
+ memmove(&strescseq.buf[strescseq.len], c, len);
+ strescseq.len += len;
+ return;
+ } else {
+ /*
+ * Here is a bug in terminals. If the user never sends
+ * some code to stop the str or esc command, then st
+ * will stop responding. But this is better than
+ * silently failing with unknown characters. At least
+ * then users will report back.
+ *
+ * In the case users ever get fixed, here is the code:
+ */
+ /*
+ * term.esc = 0;
+ * strhandle();
+ */
+ return;
+ }
+ }
+
+ /*
+ * Actions of control codes must be performed as soon they arrive
+ * because they can be embedded inside a control sequence, and
+ * they must not cause conflicts with sequences.
+ */
+ if (control) {
+ tcontrolcode(u);
+ /*
+ * control codes are not shown ever
+ */
+ return;
+ } else if (term.esc & ESC_START) {
+ if (term.esc & ESC_CSI) {
+ csiescseq.buf[csiescseq.len++] = u;
+ if (BETWEEN(u, 0x40, 0x7E)
+ || csiescseq.len >= \
+ sizeof(csiescseq.buf)-1) {
+ term.esc = 0;
+ csiparse();
+ csihandle();
+ }
+ return;
+ } else if (term.esc & ESC_ALTCHARSET) {
+ tdeftran(u);
+ } else if (term.esc & ESC_TEST) {
+ tdectest(u);
+ } else {
+ if (!eschandle(u))
+ return;
+ /* sequence already finished */
+ }
+ term.esc = 0;
+ /*
+ * All characters which form part of a sequence are not
+ * printed
+ */
+ return;
+ }
+ if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
+ selclear();
+
+ gp = &term.line[term.c.y][term.c.x];
+ if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
+ gp->mode |= ATTR_WRAP;
+ tnewline(1);
+ gp = &term.line[term.c.y][term.c.x];
+ }
+
+ if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
+ memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
+
+ if (term.c.x+width > term.col) {
+ tnewline(1);
+ gp = &term.line[term.c.y][term.c.x];
+ }
+
+ tsetchar(u, &term.c.attr, term.c.x, term.c.y);
+
+ if (width == 2) {
+ gp->mode |= ATTR_WIDE;
+ if (term.c.x+1 < term.col) {
+ gp[1].u = '\0';
+ gp[1].mode = ATTR_WDUMMY;
+ }
+ }
+ if (term.c.x+width < term.col) {
+ tmoveto(term.c.x+width, term.c.y);
+ } else {
+ term.c.state |= CURSOR_WRAPNEXT;
+ }
+}
+
+void
+tresize(int col, int row)
+{
+ int i;
+ int minrow = MIN(row, term.row);
+ int mincol = MIN(col, term.col);
+ int *bp;
+ TCursor c;
+
+ if (col < 1 || row < 1) {
+ fprintf(stderr,
+ "tresize: error resizing to %dx%d\n", col, row);
+ return;
+ }
+
+ /*
+ * slide screen to keep cursor where we expect it -
+ * tscrollup would work here, but we can optimize to
+ * memmove because we're freeing the earlier lines
+ */
+ for (i = 0; i <= term.c.y - row; i++) {
+ free(term.line[i]);
+ free(term.alt[i]);
+ }
+ /* ensure that both src and dst are not NULL */
+ if (i > 0) {
+ memmove(term.line, term.line + i, row * sizeof(Line));
+ memmove(term.alt, term.alt + i, row * sizeof(Line));
+ }
+ for (i += row; i < term.row; i++) {
+ free(term.line[i]);
+ free(term.alt[i]);
+ }
+
+ /* resize to new height */
+ term.line = xrealloc(term.line, row * sizeof(Line));
+ term.alt = xrealloc(term.alt, row * sizeof(Line));
+ term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
+ term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+
+ /* resize each row to new width, zero-pad if needed */
+ for (i = 0; i < minrow; i++) {
+ term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+ term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
+ }
+
+ /* allocate any new rows */
+ for (/* i == minrow */; i < row; i++) {
+ term.line[i] = xmalloc(col * sizeof(Glyph));
+ term.alt[i] = xmalloc(col * sizeof(Glyph));
+ }
+ if (col > term.col) {
+ bp = term.tabs + term.col;
+
+ memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
+ while (--bp > term.tabs && !*bp)
+ /* nothing */ ;
+ for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
+ *bp = 1;
+ }
+ /* update terminal size */
+ term.col = col;
+ term.row = row;
+ /* reset scrolling region */
+ tsetscroll(0, row-1);
+ /* make use of the LIMIT in tmoveto */
+ tmoveto(term.c.x, term.c.y);
+ /* Clearing both screens (it makes dirty all lines) */
+ c = term.c;
+ for (i = 0; i < 2; i++) {
+ if (mincol < col && 0 < minrow) {
+ tclearregion(mincol, 0, col - 1, minrow - 1);
+ }
+ if (0 < col && minrow < row) {
+ tclearregion(0, minrow, col - 1, row - 1);
+ }
+ tswapscreen();
+ tcursor(CURSOR_LOAD);
+ }
+ term.c = c;
+}
+
+void
+wlresize(int col, int row)
+{
+ union wld_object object;
+
+ wl.tw = MAX(1, col * wl.cw);
+ wl.th = MAX(1, row * wl.ch);
+
+ wld.oldbuffer = wld.buffer;
+ wld.buffer = wld_create_buffer(wld.ctx, wl.w, wl.h,
+ WLD_FORMAT_ARGB8888, 0);
+ wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object);
+ wl.buffer = object.ptr;
+}
+
+uchar
+sixd_to_8bit(int x)
+{
+ return x == 0 ? 0 : 0x37 + 0x28 * x;
+}
+
+int
+wlloadcolor(int i, const char *name, uint32_t *color)
+{
+ if (!name) {
+ if (BETWEEN(i, 16, 255)) { /* 256 color */
+ if (i < 6*6*6+16) { /* same colors as xterm */
+ *color = 0xff << 24 | sixd_to_8bit(((i-16)/36)%6) << 16
+ | sixd_to_8bit(((i-16)/6)%6) << 8
+ | sixd_to_8bit(((i-16)/1)%6);
+ } else { /* greyscale */
+ *color = 0xff << 24 | (0x8 + 0xa * (i-(6*6*6+16))) * 0x10101;
+ }
+ return true;
+ } else
+ name = colorname[i];
+ }
+
+ return wld_lookup_named_color(name, color);
+}
+
+void
+wlloadcols(void)
+{
+ int i;
+
+ for (i = 0; i < LEN(dc.col); i++)
+ if (!wlloadcolor(i, NULL, &dc.col[i])) {
+ if (colorname[i])
+ die("Could not allocate color '%s'\n", colorname[i]);
+ else
+ die("Could not allocate color %d\n", i);
+ }
+}
+
+int
+wlsetcolorname(int x, const char *name)
+{
+ uint32_t color;
+
+ if (!BETWEEN(x, 0, LEN(dc.col)))
+ return 1;
+
+ if (!wlloadcolor(x, name, &color))
+ return 1;
+
+ dc.col[x] = color;
+
+ return 0;
+}
+
+static void wlloadcursor(void)
+{
+ char *names[] = { mouseshape, "xterm", "ibeam", "text" };
+ int i;
+
+ cursor.theme = wl_cursor_theme_load(NULL, 32, wl.shm);
+
+ for (i = 0; !cursor.cursor && i < LEN(names); i++)
+ cursor.cursor = wl_cursor_theme_get_cursor(cursor.theme, names[i]);
+
+ cursor.surface = wl_compositor_create_surface(wl.cmp);
+}
+
+void
+wltermclear(int col1, int row1, int col2, int row2)
+{
+ uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg];
+ wld_fill_rectangle(wld.renderer, color, borderpx + col1 * wl.cw,
+ borderpx + row1 * wl.ch, (col2-col1+1) * wl.cw,
+ (row2-row1+1) * wl.ch);
+}
+
+/*
+ * Absolute coordinates.
+ */
+void
+wlclear(int x1, int y1, int x2, int y2)
+{
+ uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg];
+ wld_fill_rectangle(wld.renderer, color, x1, y1, x2 - x1, y2 - y1);
+}
+
+int
+wlloadfont(Font *f, FcPattern *pattern)
+{
+ FcPattern *match;
+ FcResult result;
+
+ match = FcFontMatch(NULL, pattern, &result);
+ if (!match)
+ return 1;
+
+ if (!(f->match = wld_font_open_pattern(wld.fontctx, match))) {
+ FcPatternDestroy(match);
+ return 1;
+ }
+
+ f->set = NULL;
+ f->pattern = FcPatternDuplicate(pattern);
+
+ f->ascent = f->match->ascent;
+ f->descent = f->match->descent;
+ f->lbearing = 0;
+ f->rbearing = f->match->max_advance;
+
+ f->height = f->ascent + f->descent;
+ f->width = f->lbearing + f->rbearing;
+
+ return 0;
+}
+
+void
+wlloadfonts(char *fontstr, double fontsize)
+{
+ FcPattern *pattern;
+ double fontval;
+ float ceilf(float);
+
+ if (fontstr[0] == '-') {
+ /* XXX: need XftXlfdParse equivalent */
+ pattern = NULL;
+ } else {
+ pattern = FcNameParse((FcChar8 *)fontstr);
+ }
+
+ if (!pattern)
+ die("st: can't open font %s\n", fontstr);
+
+ if (fontsize > 1) {
+ FcPatternDel(pattern, FC_PIXEL_SIZE);
+ FcPatternDel(pattern, FC_SIZE);
+ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
+ usedfontsize = fontsize;
+ } else {
+ if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
+ FcResultMatch) {
+ usedfontsize = fontval;
+ } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+ FcResultMatch) {
+ usedfontsize = -1;
+ } else {
+ /*
+ * Default font size is 12, if none given. This is to
+ * have a known usedfontsize value.
+ */
+ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
+ usedfontsize = 12;
+ }
+ defaultfontsize = usedfontsize;
+ }
+
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ if (wlloadfont(&dc.font, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ if (usedfontsize < 0) {
+ FcPatternGetDouble(dc.font.pattern,
+ FC_PIXEL_SIZE, 0, &fontval);
+ usedfontsize = fontval;
+ if (fontsize == 0)
+ defaultfontsize = fontval;
+ }
+
+ /* Setting character width and height. */
+ wl.cw = ceilf(dc.font.width * cwscale);
+ wl.ch = ceilf(dc.font.height * chscale);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ if (wlloadfont(&dc.ifont, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ FcPatternDel(pattern, FC_WEIGHT);
+ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ if (wlloadfont(&dc.ibfont, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+ if (wlloadfont(&dc.bfont, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ FcPatternDestroy(pattern);
+}
+
+void
+wlunloadfont(Font *f)
+{
+ wld_font_close(f->match);
+ FcPatternDestroy(f->pattern);
+ if (f->set)
+ FcFontSetDestroy(f->set);
+}
+
+void
+wlunloadfonts(void)
+{
+ /* Free the loaded fonts in the font cache. */
+ while (frclen > 0)
+ wld_font_close(frc[--frclen].font);
+
+ wlunloadfont(&dc.font);
+ wlunloadfont(&dc.bfont);
+ wlunloadfont(&dc.ifont);
+ wlunloadfont(&dc.ibfont);
+}
+
+void
+wlzoom(const Arg *arg)
+{
+ Arg larg;
+
+ larg.f = usedfontsize + arg->f;
+ wlzoomabs(&larg);
+}
+
+void
+wlzoomabs(const Arg *arg)
+{
+ wlunloadfonts();
+ wlloadfonts(usedfont, arg->f);
+ cresize(0, 0);
+ redraw();
+ /* XXX: Should the window size be updated here because wayland doesn't
+ * have a notion of hints?
+ * xhints();
+ */
+}
+
+void
+wlzoomreset(const Arg *arg)
+{
+ Arg larg;
+
+ if (defaultfontsize > 0) {
+ larg.f = defaultfontsize;
+ wlzoomabs(&larg);
+ }
+}
+
+void
+wlinit(void)
+{
+ struct wl_registry *registry;
+
+ if (!(wl.dpy = wl_display_connect(NULL)))
+ die("Can't open display\n");
+
+ registry = wl_display_get_registry(wl.dpy);
+ wl_registry_add_listener(registry, &reglistener, NULL);
+ wld.ctx = wld_wayland_create_context(wl.dpy, WLD_SHM);
+ wld.renderer = wld_create_renderer(wld.ctx);
+ wl_display_roundtrip(wl.dpy);
+
+ if (!wl.shm)
+ die("Display has no SHM\n");
+ if (!wl.seat)
+ die("Display has no seat\n");
+ if (!wl.datadevmanager)
+ die("Display has no data device manager\n");
+
+ wl.keyboard = wl_seat_get_keyboard(wl.seat);
+ wl_keyboard_add_listener(wl.keyboard, &kbdlistener, NULL);
+ wl.pointer = wl_seat_get_pointer(wl.seat);
+ wl_pointer_add_listener(wl.pointer, &ptrlistener, NULL);
+ wl.datadev = wl_data_device_manager_get_data_device(wl.datadevmanager,
+ wl.seat);
+ wl_data_device_add_listener(wl.datadev, &datadevlistener, NULL);
+
+ /* font */
+ if (!FcInit())
+ die("Could not init fontconfig.\n");
+
+ usedfont = (opt_font == NULL)? font : opt_font;
+ wld.fontctx = wld_font_create_context();
+ wlloadfonts(usedfont, 0);
+
+ wlloadcols();
+ wlloadcursor();
+
+ wl.vis = 0;
+ wl.h = 2 * borderpx + term.row * wl.ch;
+ wl.w = 2 * borderpx + term.col * wl.cw;
+
+ wl.surface = wl_compositor_create_surface(wl.cmp);
+ wl_surface_add_listener(wl.surface, &surflistener, NULL);
+
+ wl.xdgsurface = xdg_shell_get_xdg_surface(wl.shell, wl.surface);
+ xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL);
+ xdg_surface_set_app_id(wl.xdgsurface, opt_class ? opt_class : termname);
+
+ wl.xkb.ctx = xkb_context_new(0);
+ wlresettitle();
+}
+
+/*
+ * TODO: Implement something like XftDrawGlyphFontSpec in wld, and then apply a
+ * similar patch to ae1923d27533ff46400d93765e971558201ca1ee
+ */
+
+void
+wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen)
+{
+ int winx = borderpx + x * wl.cw, winy = borderpx + y * wl.ch,
+ width = charlen * wl.cw, xp, i;
+ int frcflags, charexists;
+ int u8fl, u8fblen, u8cblen, doesexist;
+ char *u8c, *u8fs;
+ Rune unicodep;
+ Font *font = &dc.font;
+ FcResult fcres;
+ FcPattern *fcpattern, *fontpattern;
+ FcFontSet *fcsets[] = { NULL };
+ FcCharSet *fccharset;
+ uint32_t fg, bg, temp;
+ int oneatatime;
+
+ frcflags = FRC_NORMAL;
+
+ if (base.mode & ATTR_ITALIC) {
+ if (base.fg == defaultfg)
+ base.fg = defaultitalic;
+ font = &dc.ifont;
+ frcflags = FRC_ITALIC;
+ } else if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
+ if (base.fg == defaultfg)
+ base.fg = defaultitalic;
+ font = &dc.ibfont;
+ frcflags = FRC_ITALICBOLD;
+ } else if (base.mode & ATTR_UNDERLINE) {
+ if (base.fg == defaultfg)
+ base.fg = defaultunderline;
+ }
+
+ if (IS_TRUECOL(base.fg)) {
+ fg = base.fg;
+ } else {
+ fg = dc.col[base.fg];
+ }
+
+ if (IS_TRUECOL(base.bg)) {
+ bg = base.bg | 0xff000000;
+ } else {
+ bg = dc.col[base.bg];
+ }
+
+ if (base.mode & ATTR_BOLD) {
+ /*
+ * change basic system colors [0-7]
+ * to bright system colors [8-15]
+ */
+ if (BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
+ fg = dc.col[base.fg + 8];
+
+ if (base.mode & ATTR_ITALIC) {
+ font = &dc.ibfont;
+ frcflags = FRC_ITALICBOLD;
+ } else {
+ font = &dc.bfont;
+ frcflags = FRC_BOLD;
+ }
+ }
+
+ if (IS_SET(MODE_REVERSE)) {
+ if (fg == dc.col[defaultfg]) {
+ fg = dc.col[defaultbg];
+ } else {
+ fg = ~(fg & 0xffffff);
+ }
+
+ if (bg == dc.col[defaultbg]) {
+ bg = dc.col[defaultfg];
+ } else {
+ bg = ~(bg & 0xffffff);
+ }
+ }
+
+ if (base.mode & ATTR_REVERSE) {
+ temp = fg;
+ fg = bg;
+ bg = temp;
+ }
+
+ if (base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) {
+ fg = (fg & (0xff << 24))
+ | ((((fg >> 16) & 0xff) / 2) << 16)
+ | ((((fg >> 8) & 0xff) / 2) << 8)
+ | ((fg & 0xff) / 2);
+ }
+
+ if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
+ fg = bg;
+
+ if (base.mode & ATTR_INVISIBLE)
+ fg = bg;
+
+ /* Intelligent cleaning up of the borders. */
+ if (x == 0) {
+ wlclear(0, (y == 0)? 0 : winy, borderpx,
+ ((y >= term.row-1)? wl.h : (winy + wl.ch)));
+ }
+ if (x + charlen >= term.col) {
+ wlclear(winx + width, (y == 0)? 0 : winy, wl.w,
+ ((y >= term.row-1)? wl.h : (winy + wl.ch)));
+ }
+ if (y == 0)
+ wlclear(winx, 0, winx + width, borderpx);
+ if (y == term.row-1)
+ wlclear(winx, winy + wl.ch, winx + width, wl.h);
+
+ /* Clean up the region we want to draw to. */
+ wld_fill_rectangle(wld.renderer, (bg & (term_alpha << 24)) | (bg & 0x00FFFFFF), winx, winy, width, wl.ch);
+ for (xp = winx; bytelen > 0;) {
+ /*
+ * Search for the range in the to be printed string of glyphs
+ * that are in the main font. Then print that range. If
+ * some glyph is found that is not in the font, do the
+ * fallback dance.
+ */
+ u8fs = s;
+ u8fblen = 0;
+ u8fl = 0;
+ oneatatime = font->width != wl.cw;
+ for (;;) {
+ u8c = s;
+ u8cblen = utf8decode(s, &unicodep, UTF_SIZ);
+ s += u8cblen;
+ bytelen -= u8cblen;
+
+ doesexist = wld_font_ensure_char(font->match, unicodep);
+ if (doesexist) {
+ u8fl++;
+ u8fblen += u8cblen;
+ if (!oneatatime && bytelen > 0)
+ continue;
+ }
+
+ if (u8fl > 0) {
+ wld_draw_text(wld.renderer,
+ font->match, fg, xp,
+ winy + font->ascent,
+ u8fs, u8fblen, NULL);
+ xp += wl.cw * u8fl;
+ }
+ break;
+ }
+ if (doesexist) {
+ if (oneatatime)
+ continue;
+ break;
+ }
+
+ /* Search the font cache. */
+ for (i = 0; i < frclen; i++) {
+ charexists = wld_font_ensure_char(frc[i].font, unicodep);
+ /* Everything correct. */
+ if (charexists && frc[i].flags == frcflags)
+ break;
+ /* We got a default font for a not found glyph. */
+ if (!charexists && frc[i].flags == frcflags \
+ && frc[i].unicodep == unicodep) {
+ break;
+ }
+ }
+
+ /* Nothing was found. */
+ if (i >= frclen) {
+ if (!font->set)
+ font->set = FcFontSort(0, font->pattern,
+ 1, 0, &fcres);
+ fcsets[0] = font->set;
+
+ /*
+ * Nothing was found in the cache. Now use
+ * some dozen of Fontconfig calls to get the
+ * font for one single character.
+ *
+ * Xft and fontconfig are design failures.
+ */
+ fcpattern = FcPatternDuplicate(font->pattern);
+ fccharset = FcCharSetCreate();
+
+ FcCharSetAddChar(fccharset, unicodep);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET,
+ fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
+
+ FcConfigSubstitute(0, fcpattern,
+ FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+
+ fontpattern = FcFontSetMatch(0, fcsets, 1,
+ fcpattern, &fcres);
+
+ /*
+ * Overwrite or create the new cache entry.
+ */
+ if (frclen >= LEN(frc)) {
+ frclen = LEN(frc) - 1;
+ wld_font_close(frc[frclen].font);
+ frc[frclen].unicodep = 0;
+ }
+
+ frc[frclen].font = wld_font_open_pattern(wld.fontctx,
+ fontpattern);
+ frc[frclen].flags = frcflags;
+ frc[frclen].unicodep = unicodep;
+
+ i = frclen;
+ frclen++;
+
+ FcPatternDestroy(fcpattern);
+ FcCharSetDestroy(fccharset);
+ }
+
+ wld_draw_text(wld.renderer, frc[i].font, fg,
+ xp, winy + frc[i].font->ascent,
+ u8c, u8cblen, NULL);
+
+ xp += wl.cw * wcwidth(unicodep);
+ }
+
+ if (base.mode & ATTR_UNDERLINE) {
+ wld_fill_rectangle(wld.renderer, fg, winx, winy + font->ascent + 1,
+ width, 1);
+ }
+
+ if (base.mode & ATTR_STRUCK) {
+ wld_fill_rectangle(wld.renderer, fg, winx, winy + 2 * font->ascent / 3,
+ width, 1);
+ }
+}
+
+void
+wldrawglyph(Glyph g, int x, int y)
+{
+ static char buf[UTF_SIZ];
+ size_t len = utf8encode(g.u, buf);
+ int width = g.mode & ATTR_WIDE ? 2 : 1;
+
+ wldraws(buf, g, x, y, width, len);
+}
+
+void
+wldrawcursor(void)
+{
+ static int oldx = 0, oldy = 0;
+ int curx;
+ Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs};
+
+ LIMIT(oldx, 0, term.col-1);
+ LIMIT(oldy, 0, term.row-1);
+
+ curx = term.c.x;
+
+ /* adjust position if in dummy */
+ if (term.line[oldy][oldx].mode & ATTR_WDUMMY)
+ oldx--;
+ if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
+ curx--;
+
+ g.u = term.line[term.c.y][term.c.x].u;
+
+ /* remove the old cursor */
+ wldrawglyph(term.line[oldy][oldx], oldx, oldy);
+ if (oldx != curx || oldy != term.c.y) {
+ wl_surface_damage(wl.surface, borderpx + oldx * wl.cw,
+ borderpx + oldy * wl.ch, wl.cw, wl.ch);
+ }
+
+ if (IS_SET(MODE_HIDE))
+ return;
+ uint32_t cs = dc.col[defaultcs] & (term_alpha << 24);
+ /* draw the new one */
+ if (wl.state & WIN_FOCUSED) {
+ switch (wl.cursor) {
+ case 0: /* Blinking Block */
+ case 1: /* Blinking Block (Default) */
+ case 2: /* Steady Block */
+ if (IS_SET(MODE_REVERSE)) {
+ g.mode |= ATTR_REVERSE;
+ g.fg = defaultcs;
+ g.bg = defaultfg;
+ }
+
+ g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
+ wldrawglyph(g, term.c.x, term.c.y);
+ break;
+ case 3: /* Blinking Underline */
+ case 4: /* Steady Underline */
+ wld_fill_rectangle(wld.renderer, cs,
+ borderpx + curx * wl.cw,
+ borderpx + (term.c.y + 1) * wl.ch - cursorthickness,
+ wl.cw, cursorthickness);
+ break;
+ case 5: /* Blinking bar */
+ case 6: /* Steady bar */
+ wld_fill_rectangle(wld.renderer, cs,
+ borderpx + curx * wl.cw,
+ borderpx + term.c.y * wl.ch,
+ cursorthickness, wl.ch);
+ break;
+ }
+ } else {
+ wld_fill_rectangle(wld.renderer, cs,
+ borderpx + curx * wl.cw,
+ borderpx + term.c.y * wl.ch,
+ wl.cw - 1, 1);
+ wld_fill_rectangle(wld.renderer, cs,
+ borderpx + curx * wl.cw,
+ borderpx + term.c.y * wl.ch,
+ 1, wl.ch - 1);
+ wld_fill_rectangle(wld.renderer, cs,
+ borderpx + (curx + 1) * wl.cw - 1,
+ borderpx + term.c.y * wl.ch,
+ 1, wl.ch - 1);
+ wld_fill_rectangle(wld.renderer, cs,
+ borderpx + curx * wl.cw,
+ borderpx + (term.c.y + 1) * wl.ch - 1,
+ wl.cw, 1);
+ }
+ wl_surface_damage(wl.surface, borderpx + curx * wl.cw,
+ borderpx + term.c.y * wl.ch, wl.cw, wl.ch);
+ oldx = curx, oldy = term.c.y;
+}
+
+void
+wlsettitle(char *title)
+{
+ xdg_surface_set_title(wl.xdgsurface, title);
+}
+
+void
+wlresettitle(void)
+{
+ wlsettitle(opt_title ? opt_title : "st");
+}
+
+void
+redraw(void)
+{
+ tfulldirt();
+}
+
+void
+draw(void)
+{
+ int y, y0;
+
+ for (y = 0; y <= term.bot; ++y) {
+ if (!term.dirty[y])
+ continue;
+ for (y0 = y; y <= term.bot && term.dirty[y]; ++y);
+ wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch,
+ wl.w, (y - y0) * wl.ch);
+ }
+
+ wld_set_target_buffer(wld.renderer, wld.buffer);
+ drawregion(0, 0, term.col, term.row);
+ wl.framecb = wl_surface_frame(wl.surface);
+ wl_callback_add_listener(wl.framecb, &framelistener, NULL);
+ wld_flush(wld.renderer);
+ wl_surface_attach(wl.surface, wl.buffer, 0, 0);
+ wl_surface_commit(wl.surface);
+ /* need to wait to destroy the old buffer until we commit the new
+ * buffer */
+ if (wld.oldbuffer) {
+ wld_buffer_unreference(wld.oldbuffer);
+ wld.oldbuffer = 0;
+ }
+ needdraw = false;
+}
+
+void
+drawregion(int x1, int y1, int x2, int y2)
+{
+ int ic, ib, x, y, ox;
+ Glyph base, new;
+ char buf[DRAW_BUF_SIZ];
+ int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
+
+ for (y = y1; y < y2; y++) {
+ if (!term.dirty[y])
+ continue;
+
+ wltermclear(0, y, term.col, y);
+ term.dirty[y] = 0;
+ base = term.line[y][0];
+ ic = ib = ox = 0;
+ for (x = x1; x < x2; x++) {
+ new = term.line[y][x];
+ if (new.mode == ATTR_WDUMMY)
+ continue;
+ if (ena_sel && selected(x, y))
+ new.mode ^= ATTR_REVERSE;
+ if (ib > 0 && (ATTRCMP(base, new)
+ || ib >= DRAW_BUF_SIZ-UTF_SIZ)) {
+ wldraws(buf, base, ox, y, ic, ib);
+ ic = ib = 0;
+ }
+ if (ib == 0) {
+ ox = x;
+ base = new;
+ }
+
+ ib += utf8encode(new.u, buf+ib);
+ ic += (new.mode & ATTR_WIDE)? 2 : 1;
+ }
+ if (ib > 0)
+ wldraws(buf, base, ox, y, ic, ib);
+ }
+ wldrawcursor();
+}
+
+void
+wlseturgency(int add)
+{
+ /* XXX: no urgency equivalent yet in wayland */
+}
+
+int
+match(uint mask, uint state)
+{
+ return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod));
+}
+
+void
+numlock(const Arg *dummy)
+{
+ term.numlock ^= 1;
+}
+
+char*
+kmap(xkb_keysym_t k, uint state)
+{
+ Key *kp;
+ int i;
+
+ /* Check for mapped keys out of X11 function keys. */
+ for (i = 0; i < LEN(mappedkeys); i++) {
+ if (mappedkeys[i] == k)
+ break;
+ }
+ if (i == LEN(mappedkeys)) {
+ if ((k & 0xFFFF) < 0xFD00)
+ return NULL;
+ }
+
+ for (kp = key; kp < key + LEN(key); kp++) {
+ if (kp->k != k)
+ continue;
+
+ if (!match(kp->mask, state))
+ continue;
+
+ if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
+ continue;
+ if (term.numlock && kp->appkey == 2)
+ continue;
+
+ if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
+ continue;
+
+ if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
+ continue;
+
+ return kp->s;
+ }
+
+ return NULL;
+}
+
+void
+cresize(int width, int height)
+{
+ int col, row;
+
+ if (width != 0)
+ wl.w = width;
+ if (height != 0)
+ wl.h = height;
+
+ col = (wl.w - 2 * borderpx) / wl.cw;
+ row = (wl.h - 2 * borderpx) / wl.ch;
+
+ tresize(col, row);
+ wlresize(col, row);
+ ttyresize();
+}
+
+void
+regglobal(void *data, struct wl_registry *registry, uint32_t name,
+ const char *interface, uint32_t version)
+{
+ if (strcmp(interface, "wl_compositor") == 0) {
+ wl.cmp = wl_registry_bind(registry, name,
+ &wl_compositor_interface, 3);
+ } else if (strcmp(interface, "xdg_shell") == 0) {
+ wl.shell = wl_registry_bind(registry, name,
+ &xdg_shell_interface, 1);
+ xdg_shell_add_listener(wl.shell, &xdgshelllistener, NULL);
+ xdg_shell_use_unstable_version(wl.shell,
+ XDG_SHELL_VERSION_CURRENT);
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ wl.seat = wl_registry_bind(registry, name,
+ &wl_seat_interface, 4);
+ } else if (strcmp(interface, "wl_data_device_manager") == 0) {
+ wl.datadevmanager = wl_registry_bind(registry, name,
+ &wl_data_device_manager_interface, 1);
+ } else if (strcmp(interface, "wl_output") == 0) {
+ /* bind to outputs so we can get surface enter events */
+ wl_registry_bind(registry, name, &wl_output_interface, 2);
+ }
+}
+
+void
+regglobalremove(void *data, struct wl_registry *registry, uint32_t name)
+{
+}
+
+void
+surfenter(void *data, struct wl_surface *surface, struct wl_output *output)
+{
+ wl.vis++;
+ if (!(wl.state & WIN_VISIBLE))
+ wl.state |= WIN_VISIBLE;
+}
+
+void
+surfleave(void *data, struct wl_surface *surface, struct wl_output *output)
+{
+ if (--wl.vis == 0)
+ wl.state &= ~WIN_VISIBLE;
+}
+
+void
+framedone(void *data, struct wl_callback *callback, uint32_t msecs)
+{
+ wl_callback_destroy(callback);
+ wl.framecb = NULL;
+ if (needdraw && wl.state & WIN_VISIBLE) {
+ draw();
+ }
+}
+
+void
+kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd,
+ uint32_t size)
+{
+ char *string;
+
+ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+ close(fd);
+ return;
+ }
+
+ string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+
+ if (string == MAP_FAILED) {
+ close(fd);
+ return;
+ }
+
+ wl.xkb.keymap = xkb_keymap_new_from_string(wl.xkb.ctx, string,
+ XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+ munmap(string, size);
+ close(fd);
+ wl.xkb.state = xkb_state_new(wl.xkb.keymap);
+
+ wl.xkb.ctrl = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_CTRL);
+ wl.xkb.alt = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_ALT);
+ wl.xkb.shift = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_SHIFT);
+ wl.xkb.logo = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_LOGO);
+
+ wl.xkb.mods = 0;
+}
+
+void
+kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial,
+ struct wl_surface *surface, struct wl_array *keys)
+{
+ wl.state |= WIN_FOCUSED;
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[I", 3);
+ /* need to redraw the cursor */
+ needdraw = true;
+}
+
+void
+kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial,
+ struct wl_surface *surface)
+{
+ /* selection offers are invalidated when we lose keyboard focus */
+ wl.seloffer = NULL;
+ wl.state &= ~WIN_FOCUSED;
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[O", 3);
+ /* need to redraw the cursor */
+ needdraw = true;
+ /* disable key repeat */
+ repeat.len = 0;
+}
+
+void
+kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time,
+ uint32_t key, uint32_t state)
+{
+ xkb_keysym_t ksym;
+ char buf[32], *str;
+ int len;
+ Rune c;
+ Shortcut *bp;
+
+ if (IS_SET(MODE_KBDLOCK))
+ return;
+
+ if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
+ if (repeat.key == key)
+ repeat.len = 0;
+ return;
+ }
+
+ ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8);
+ len = xkb_keysym_to_utf8(ksym, buf, sizeof buf);
+ if (len > 0)
+ --len;
+
+ /* 1. shortcuts */
+ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+ if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) {
+ bp->func(&(bp->arg));
+ return;
+ }
+ }
+
+ /* 2. custom keys from config.h */
+ if ((str = kmap(ksym, wl.xkb.mods))) {
+ len = strlen(str);
+ goto send;
+ }
+
+ /* 3. composed string from input method */
+ if (len == 0)
+ return;
+ if (len == 1 && wl.xkb.mods & MOD_MASK_ALT) {
+ if (IS_SET(MODE_8BIT)) {
+ if (*buf < 0177) {
+ c = *buf | 0x80;
+ len = utf8encode(c, buf);
+ }
+ } else {
+ buf[1] = buf[0];
+ buf[0] = '\033';
+ len = 2;
+ }
+ }
+ /* convert character to control character */
+ else if (len == 1 && wl.xkb.mods & MOD_MASK_CTRL) {
+ if ((*buf >= '@' && *buf < '\177') || *buf == ' ')
+ *buf &= 0x1F;
+ else if (*buf == '2') *buf = '\000';
+ else if (*buf >= '3' && *buf <= '7')
+ *buf -= ('3' - '\033');
+ else if (*buf == '8') *buf = '\177';
+ else if (*buf == '/') *buf = '_' & 0x1F;
+ }
+
+ str = buf;
+
+send:
+ memcpy(repeat.str, str, len);
+ repeat.key = key;
+ repeat.len = len;
+ repeat.started = false;
+ clock_gettime(CLOCK_MONOTONIC, &repeat.last);
+ ttysend(str, len);
+}
+
+void
+kbdmodifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial,
+ uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group)
+{
+ xkb_mod_mask_t mod_mask;
+
+ xkb_state_update_mask(wl.xkb.state, dep, lat, lck, group, 0, 0);
+
+ mod_mask = xkb_state_serialize_mods(wl.xkb.state, XKB_STATE_MODS_EFFECTIVE);
+ wl.xkb.mods = 0;
+
+ if (mod_mask & (1 << wl.xkb.ctrl))
+ wl.xkb.mods |= MOD_MASK_CTRL;
+ if (mod_mask & (1 << wl.xkb.alt))
+ wl.xkb.mods |= MOD_MASK_ALT;
+ if (mod_mask & (1 << wl.xkb.shift))
+ wl.xkb.mods |= MOD_MASK_SHIFT;
+ if (mod_mask & (1 << wl.xkb.logo))
+ wl.xkb.mods |= MOD_MASK_LOGO;
+}
+
+void
+kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate,
+ int32_t delay)
+{
+ keyrepeatdelay = delay;
+ keyrepeatinterval = 1000 / rate;
+}
+
+void
+ptrenter(void *data, struct wl_pointer *pointer, uint32_t serial,
+ struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
+{
+ struct wl_cursor_image *img = cursor.cursor->images[0];
+ struct wl_buffer *buffer;
+
+ wl_pointer_set_cursor(pointer, serial, cursor.surface,
+ img->hotspot_x, img->hotspot_y);
+ buffer = wl_cursor_image_get_buffer(img);
+ wl_surface_attach(cursor.surface, buffer, 0, 0);
+ wl_surface_damage(cursor.surface, 0, 0, img->width, img->height);
+ wl_surface_commit(cursor.surface);
+}
+
+void
+ptrleave(void *data, struct wl_pointer *pointer, uint32_t serial,
+ struct wl_surface *surface)
+{
+}
+
+void
+ptrmotion(void *data, struct wl_pointer * pointer, uint32_t serial,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ int oldey, oldex, oldsby, oldsey;
+
+ if (IS_SET(MODE_MOUSE)) {
+ wlmousereportmotion(x, y);
+ return;
+ }
+
+ wl.px = wl_fixed_to_int(x);
+ wl.py = wl_fixed_to_int(y);
+
+ if (!sel.mode)
+ return;
+
+ sel.mode = SEL_READY;
+ oldey = sel.oe.y;
+ oldex = sel.oe.x;
+ oldsby = sel.nb.y;
+ oldsey = sel.ne.y;
+ getbuttoninfo();
+
+ if (oldey != sel.oe.y || oldex != sel.oe.x)
+ tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+}
+
+void
+ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ Mousekey *mk;
+
+ if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) {
+ wlmousereportbutton(button, state);
+ return;
+ }
+
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ if (button == BTN_MIDDLE) {
+ selpaste(NULL);
+ } else if (button == BTN_LEFT) {
+ if (sel.mode == SEL_READY) {
+ getbuttoninfo();
+ selcopy(serial);
+ } else
+ selclear();
+ sel.mode = SEL_IDLE;
+ tsetdirt(sel.nb.y, sel.ne.y);
+ }
+ break;
+
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+ for (mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) {
+ if (button == mk->b && match(mk->mask, wl.xkb.mods)) {
+ ttysend(mk->s, strlen(mk->s));
+ return;
+ }
+ }
+
+ if (button == BTN_LEFT) {
+ /* Clear previous selection, logically and visually. */
+ selclear();
+ sel.mode = SEL_EMPTY;
+ sel.type = SEL_REGULAR;
+ sel.oe.x = sel.ob.x = x2col(wl.px);
+ sel.oe.y = sel.ob.y = y2row(wl.py);
+
+ /*
+ * If the user clicks below predefined timeouts
+ * specific snapping behaviour is exposed.
+ */
+ if (time - sel.tclick2 <= tripleclicktimeout) {
+ sel.snap = SNAP_LINE;
+ } else if (time - sel.tclick1 <= doubleclicktimeout) {
+ sel.snap = SNAP_WORD;
+ } else {
+ sel.snap = 0;
+ }
+ selnormalize();
+
+ if (sel.snap != 0)
+ sel.mode = SEL_READY;
+ tsetdirt(sel.nb.y, sel.ne.y);
+ sel.tclick2 = sel.tclick1;
+ sel.tclick1 = time;
+ }
+ break;
+ }
+}
+
+void
+ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis,
+ wl_fixed_t value)
+{
+ Axiskey *ak;
+ int dir = value > 0 ? +1 : -1;
+
+ if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) {
+ wlmousereportaxis(axis, value);
+ return;
+ }
+
+ for (ak = ashortcuts; ak < ashortcuts + LEN(ashortcuts); ak++) {
+ if (axis == ak->axis && dir == ak->dir
+ && match(ak->mask, wl.xkb.mods)) {
+ ttysend(ak->s, strlen(ak->s));
+ return;
+ }
+ }
+}
+
+void
+xdgshellping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+void
+xdgsurfconfigure(void *data, struct xdg_surface *surf, int32_t w, int32_t h,
+ struct wl_array *states, uint32_t serial)
+{
+ xdg_surface_ack_configure(surf, serial);
+ if (w == wl.w && h == wl.h)
+ return;
+ wl.configured = true;
+ cresize(w, h);
+}
+
+void
+xdgsurfclose(void *data, struct xdg_surface *surf)
+{
+ /* Send SIGHUP to shell */
+ kill(pid, SIGHUP);
+ exit(0);
+}
+
+void
+datadevoffer(void *data, struct wl_data_device *datadev,
+ struct wl_data_offer *offer)
+{
+ wl_data_offer_add_listener(offer, &dataofferlistener, NULL);
+}
+
+void
+datadeventer(void *data, struct wl_data_device *datadev, uint32_t serial,
+ struct wl_surface *surf, wl_fixed_t x, wl_fixed_t y,
+ struct wl_data_offer *offer)
+{
+}
+
+void
+datadevleave(void *data, struct wl_data_device *datadev)
+{
+}
+
+void
+datadevmotion(void *data, struct wl_data_device *datadev, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+}
+
+void
+datadevdrop(void *data, struct wl_data_device *datadev)
+{
+}
+
+void
+datadevselection(void *data, struct wl_data_device *datadev,
+ struct wl_data_offer *offer)
+{
+ if (offer && (uintptr_t) wl_data_offer_get_user_data(offer) == 1)
+ wl.seloffer = offer;
+ else
+ wl.seloffer = NULL;
+}
+
+void
+dataofferoffer(void *data, struct wl_data_offer *offer, const char *mimetype)
+{
+ /* mark the offer as usable if it supports plain text */
+ if (strncmp(mimetype, "text/plain", 10) == 0)
+ wl_data_offer_set_user_data(offer, (void *)(uintptr_t) 1);
+}
+
+void
+datasrctarget(void *data, struct wl_data_source *source, const char *mimetype)
+{
+}
+
+void
+datasrcsend(void *data, struct wl_data_source *source, const char *mimetype,
+ int32_t fd)
+{
+ char *buf = sel.primary;
+ int len = strlen(sel.primary);
+ ssize_t ret;
+ while ((ret = write(fd, buf, MIN(len, BUFSIZ))) > 0) {
+ len -= ret;
+ buf += ret;
+ }
+ close(fd);
+}
+
+void
+datasrccancelled(void *data, struct wl_data_source *source)
+{
+ if (sel.source == source) {
+ sel.source = NULL;
+ selclear();
+ }
+ wl_data_source_destroy(source);
+}
+
+void
+run(void)
+{
+ fd_set rfd;
+ int wlfd = wl_display_get_fd(wl.dpy), blinkset = 0;
+ struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
+ ulong msecs;
+
+ ttynew();
+ /* Look for initial configure. */
+ wl_display_roundtrip(wl.dpy);
+ if (!wl.configured)
+ cresize(wl.w, wl.h);
+ draw();
+
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ lastblink = last;
+
+ for (;;) {
+ FD_ZERO(&rfd);
+ FD_SET(cmdfd, &rfd);
+ FD_SET(wlfd, &rfd);
+
+ if (pselect(MAX(wlfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
+ if (errno == EINTR)
+ continue;
+ die("select failed: %s\n", strerror(errno));
+ }
+
+ if (FD_ISSET(cmdfd, &rfd)) {
+ ttyread();
+ if (blinktimeout) {
+ blinkset = tattrset(ATTR_BLINK);
+ if (!blinkset)
+ MODBIT(term.mode, 0, MODE_BLINK);
+ }
+ }
+
+ if (FD_ISSET(wlfd, &rfd)) {
+ if (wl_display_dispatch(wl.dpy) == -1)
+ die("Connection error\n");
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ msecs = -1;
+
+ if (blinkset && blinktimeout) {
+ if (TIMEDIFF(now, lastblink) >= blinktimeout) {
+ tsetdirtattr(ATTR_BLINK);
+ term.mode ^= MODE_BLINK;
+ lastblink = now;
+ } else {
+ msecs = MIN(msecs, blinktimeout - \
+ TIMEDIFF(now, lastblink));
+ }
+ }
+ if (repeat.len > 0) {
+ if (TIMEDIFF(now, repeat.last) >= \
+ (repeat.started ? keyrepeatinterval : \
+ keyrepeatdelay)) {
+ repeat.started = true;
+ repeat.last = now;
+ ttysend(repeat.str, repeat.len);
+ } else {
+ msecs = MIN(msecs, (repeat.started ? \
+ keyrepeatinterval : keyrepeatdelay) - \
+ TIMEDIFF(now, repeat.last));
+ }
+ }
+
+ if (needdraw) {
+ if (!wl.framecb) {
+ draw();
+ }
+ }
+
+ if (msecs == -1) {
+ tv = NULL;
+ } else {
+ drawtimeout.tv_nsec = 1E6 * msecs;
+ drawtimeout.tv_sec = 0;
+ tv = &drawtimeout;
+ }
+
+ wl_display_dispatch_pending(wl.dpy);
+ wl_display_flush(wl.dpy);
+ }
+}
+
+void
+usage(void)
+{
+ die("%s " VERSION " (c) 2010-2015 st engineers\n"
+ "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
+ " [-i] [-t title] [-T title] [-w windowid] [-e command ...]"
+ " [command ...]\n"
+ " st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
+ " [-i] [-t title] [-T title] [-w windowid] [-l line]"
+ " [stty_args ...]\n",
+ argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ ARGBEGIN {
+ case 'a':
+ allowaltscreen = 0;
+ break;
+ case 'c':
+ opt_class = EARGF(usage());
+ break;
+ case 'e':
+ if (argc > 0)
+ --argc, ++argv;
+ goto run;
+ case 'f':
+ opt_font = EARGF(usage());
+ break;
+ case 'o':
+ opt_io = EARGF(usage());
+ break;
+ case 'l':
+ opt_line = EARGF(usage());
+ break;
+ case 't':
+ case 'T':
+ opt_title = EARGF(usage());
+ break;
+ case 'w':
+ opt_embed = EARGF(usage());
+ break;
+ case 'v':
+ default:
+ usage();
+ } ARGEND;
+
+run:
+ if (argc > 0) {
+ /* eat all remaining arguments */
+ opt_cmd = argv;
+ if (!opt_title && !opt_line)
+ opt_title = basename(xstrdup(argv[0]));
+ }
+ setlocale(LC_CTYPE, "");
+ tnew(80, 24);
+ wlinit();
+ selinit();
+ run();
+
+ return 0;
+}
+
diff --git a/src/wld/.gitignore b/src/wld/.gitignore
new file mode 100644
index 0000000..445ef3b
--- /dev/null
+++ b/src/wld/.gitignore
@@ -0,0 +1,11 @@
+*.o
+*.lo
+.*.sw*
+
+/.deps/
+/libwld.a
+/libwld.so*
+/wld.pc
+/protocol/wayland-drm-client-protocol.h
+/protocol/wayland-drm-protocol.c
+
diff --git a/src/wld/COPYING b/src/wld/COPYING
new file mode 100644
index 0000000..7da88e5
--- /dev/null
+++ b/src/wld/COPYING
@@ -0,0 +1,20 @@
+Copyright (c) 2013, 2014 Michael Forney
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/src/wld/Makefile b/src/wld/Makefile
new file mode 100644
index 0000000..b5db1c8
--- /dev/null
+++ b/src/wld/Makefile
@@ -0,0 +1,186 @@
+# wld: Makefile
+
+include config.mk
+
+#PREFIX ?= /usr/local
+#LIBDIR ?= $(PREFIX)/lib
+#INCLUDEDIR ?= $(PREFIX)/include
+#PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
+
+PKG_CONFIG ?= pkg-config
+WAYLAND_SCANNER ?= wayland-scanner
+
+VERSION_MAJOR := 0
+VERSION_MINOR := 0
+VERSION := $(VERSION_MAJOR).$(VERSION_MINOR)
+
+WLD_LIB_LINK := libwld.so
+WLD_LIB_SONAME := $(WLD_LIB_LINK).$(VERSION_MAJOR)
+WLD_LIB := $(WLD_LIB_LINK).$(VERSION)
+
+TARGETS := wld.pc
+CLEAN_FILES :=
+
+WLD_REQUIRES = fontconfig pixman-1
+WLD_REQUIRES_PRIVATE = freetype2
+WLD_SOURCES = \
+ buffer.c \
+ buffered_surface.c \
+ color.c \
+ context.c \
+ font.c \
+ renderer.c \
+ surface.c
+WLD_HEADERS = wld.h
+
+ifeq ($(ENABLE_DRM),1)
+ WLD_REQUIRES_PRIVATE += libdrm
+ WLD_SOURCES += drm.c dumb.c
+ WLD_HEADERS += drm.h
+
+ ifneq ($(findstring intel,$(DRM_DRIVERS)),)
+ WLD_REQUIRES_PRIVATE += libdrm_intel
+ WLD_SOURCES += intel.c intel/batch.c
+ WLD_CPPFLAGS += -DWITH_DRM_INTEL=1
+ endif
+
+ ifneq ($(findstring nouveau,$(DRM_DRIVERS)),)
+ WLD_REQUIRES_PRIVATE += libdrm_nouveau
+ WLD_SOURCES += nouveau.c
+ WLD_CPPFLAGS += -DWITH_DRM_NOUVEAU=1
+ endif
+endif
+
+ifeq ($(ENABLE_PIXMAN),1)
+ WLD_SOURCES += pixman.c
+ WLD_HEADERS += pixman.h
+endif
+
+ifeq ($(ENABLE_WAYLAND),1)
+ WLD_REQUIRES_PRIVATE += wayland-client
+ WLD_SOURCES += wayland.c
+ WLD_HEADERS += wayland.h
+
+ ifneq ($(findstring shm,$(WAYLAND_INTERFACES)),)
+ WLD_SOURCES += wayland-shm.c
+ WLD_CPPFLAGS += -DWITH_WAYLAND_SHM=1
+ endif
+
+ ifneq ($(findstring drm,$(WAYLAND_INTERFACES)),)
+ WLD_SOURCES += wayland-drm.c protocol/wayland-drm-protocol.c
+ WLD_CPPFLAGS += -DWITH_WAYLAND_DRM=1
+ endif
+endif
+
+ifeq ($(if $(V),$(V),0), 0)
+ define quiet
+ @echo " $1 $@"
+ @$(if $2,$2,$($1))
+ endef
+else
+ quiet = $(if $2,$2,$($1))
+endif
+
+WLD_STATIC_OBJECTS = $(WLD_SOURCES:%.c=%.o)
+WLD_SHARED_OBJECTS = $(WLD_SOURCES:%.c=%.lo)
+WLD_PACKAGES = $(WLD_REQUIRES) $(WLD_REQUIRES_PRIVATE)
+WLD_PACKAGE_CFLAGS ?= $(call pkgconfig,$(WLD_PACKAGES),cflags,CFLAGS)
+WLD_PACKAGE_LIBS ?= $(call pkgconfig,$(WLD_PACKAGES),libs,LIBS)
+
+FINAL_CFLAGS = $(CFLAGS) -fvisibility=hidden -std=c99
+FINAL_CPPFLAGS = $(CPPFLAGS) -D_XOPEN_SOURCE=700
+
+# Warning/error flags
+FINAL_CFLAGS += -Werror=implicit-function-declaration -Werror=implicit-int \
+ -Werror=pointer-sign -Werror=pointer-arith \
+ -Wall -Wno-missing-braces
+
+ifeq ($(ENABLE_DEBUG),1)
+ FINAL_CPPFLAGS += -DENABLE_DEBUG=1
+ FINAL_CFLAGS += -g
+else
+ FINAL_CPPFLAGS += -DNDEBUG
+endif
+
+ifeq ($(ENABLE_STATIC),1)
+ TARGETS += libwld.a
+ CLEAN_FILES += $(WLD_STATIC_OBJECTS)
+endif
+
+ifeq ($(ENABLE_SHARED),1)
+ TARGETS += $(WLD_LIB) $(WLD_LIB_LINK) $(WLD_LIB_SONAME)
+ CLEAN_FILES += $(WLD_SHARED_OBJECTS)
+endif
+
+CLEAN_FILES += $(TARGETS)
+
+compile = $(call quiet,CC) $(FINAL_CPPFLAGS) $(FINAL_CFLAGS) -c -o $@ $< \
+ -MMD -MP -MF .deps/$(basename $<).d -MT $(basename $@).o -MT $(basename $@).lo
+link = $(call quiet,CCLD,$(CC)) $(LDFLAGS) -o $@ $^
+pkgconfig = $(sort $(foreach pkg,$(1),$(if $($(pkg)_$(3)),$($(pkg)_$(3)), \
+ $(shell $(PKG_CONFIG) --$(2) $(pkg)))))
+
+.PHONY: all
+all: $(TARGETS)
+
+include $(foreach dir,intel protocol,$(dir)/local.mk)
+
+.deps:
+ @mkdir "$@"
+
+%.o: %.c | .deps
+ $(compile) $(WLD_CPPFLAGS) $(WLD_PACKAGE_CFLAGS)
+
+%.lo: %.c | .deps
+ $(compile) $(WLD_CPPFLAGS) $(WLD_PACKAGE_CFLAGS) -fPIC
+
+wayland-drm.o wayland-drm.lo: protocol/wayland-drm-client-protocol.h
+
+wld.pc: wld.pc.in
+ $(call quiet,GEN,sed) \
+ -e "s:@VERSION@:$(VERSION):" \
+ -e "s:@PREFIX@:$(PREFIX):" \
+ -e "s:@LIBDIR@:$(LIBDIR):" \
+ -e "s:@INCLUDEDIR@:$(INCLUDEDIR):" \
+ -e "s:@WLD_REQUIRES@:$(WLD_REQUIRES):" \
+ -e "s:@WLD_REQUIRES_PRIVATE@:$(WLD_REQUIRES_PRIVATE):" \
+ $< > $@
+
+libwld.a: $(WLD_STATIC_OBJECTS)
+ $(call quiet,AR) cr $@ $^
+
+$(WLD_LIB): $(WLD_SHARED_OBJECTS)
+ $(link) $(WLD_PACKAGE_LIBS) -shared -Wl,-soname,$(WLD_LIB_SONAME),-no-undefined
+
+$(WLD_LIB_SONAME) $(WLD_LIB_LINK): $(WLD_LIB)
+ $(call quiet,SYM,ln -sf) $< $@
+
+$(foreach dir,LIB PKGCONFIG,$(DESTDIR)$($(dir)DIR)) $(DESTDIR)$(INCLUDEDIR)/wld:
+ mkdir -p $@
+
+.PHONY: install-wld.pc
+install-wld.pc: wld.pc | $(DESTDIR)$(PKGCONFIGDIR)
+ install -m 644 $< $(DESTDIR)$(PKGCONFIGDIR)
+
+.PHONY: install-libwld.a
+install-libwld.a: libwld.a | $(DESTDIR)$(LIBDIR)
+ install -m 644 $< $(DESTDIR)$(LIBDIR)
+
+.PHONY: install-$(WLD_LIB)
+install-$(WLD_LIB): $(WLD_LIB) | $(DESTDIR)$(LIBDIR)
+ install -m 755 $< $(DESTDIR)$(LIBDIR)
+
+.PHONY: install-$(WLD_LIB_LINK) install-$(WLD_LIB_SONAME)
+install-$(WLD_LIB_LINK) install-$(WLD_LIB_SONAME): install-$(WLD_LIB) | $(DESTDIR)$(LIBDIR)
+ ln -sf $(WLD_LIB) $(DESTDIR)$(LIBDIR)/${@:install-%=%}
+
+.PHONY: install
+install: $(TARGETS:%=install-%) | $(foreach dir,LIB PKGCONFIG,$(DESTDIR)$($(dir)DIR)) $(DESTDIR)$(INCLUDEDIR)/wld
+ install -m 644 $(WLD_HEADERS) $(DESTDIR)$(INCLUDEDIR)/wld
+
+.PHONY: clean
+clean:
+ rm -rf $(CLEAN_FILES)
+
+-include .deps/*.d
+
diff --git a/src/wld/README.md b/src/wld/README.md
new file mode 100644
index 0000000..1326c25
--- /dev/null
+++ b/src/wld/README.md
@@ -0,0 +1,16 @@
+wld
+===
+wld is a drawing library that targets Wayland. The [swc Wayland compositor
+library](https://github.com/michaelforney/swc) uses wld.
+
+Installing
+==========
+To build and install wld, simply use:
+
+```Bash
+make
+make install
+```
+
+Various flags may be set in config.mk. You will likely want to compile
+using only intel or noveau, not both.
diff --git a/src/wld/TODO b/src/wld/TODO
new file mode 100644
index 0000000..9915589
--- /dev/null
+++ b/src/wld/TODO
@@ -0,0 +1,6 @@
+TODO
+====
+- Non-monochrome text rendering
+ - Probably requires 3d engine blending for intel backend
+- Add doxygen documentation
+
diff --git a/src/wld/buffer.c b/src/wld/buffer.c
new file mode 100644
index 0000000..46b1b3b
--- /dev/null
+++ b/src/wld/buffer.c
@@ -0,0 +1,137 @@
+/* wld: buffer.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wld-private.h"
+
+void buffer_initialize(struct buffer * buffer,
+ const struct wld_buffer_impl * impl,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ *((const struct wld_buffer_impl **) &buffer->base.impl) = impl;
+ buffer->base.width = width;
+ buffer->base.height = height;
+ buffer->base.format = format;
+ buffer->base.pitch = pitch;
+ buffer->base.map = NULL;
+ buffer->references = 1;
+ buffer->map_references = 0;
+ buffer->exporters = NULL;
+ buffer->destructors = NULL;
+ pixman_region32_init_rect(&buffer->base.damage, 0, 0, width, height);
+}
+
+EXPORT
+bool wld_map(struct wld_buffer * base)
+{
+ struct buffer * buffer = (void *) base;
+
+ if (buffer->map_references == 0 && !buffer->base.impl->map(buffer))
+ return false;
+
+ ++buffer->map_references;
+ return true;
+}
+
+EXPORT
+bool wld_unmap(struct wld_buffer * base)
+{
+ struct buffer * buffer = (void *) base;
+
+ if (buffer->map_references == 0
+ || (buffer->map_references == 1 && !buffer->base.impl->unmap(buffer)))
+ {
+ return false;
+ }
+
+ --buffer->map_references;
+ return true;
+}
+
+EXPORT
+bool wld_export(struct wld_buffer * base,
+ uint32_t type, union wld_object * object)
+{
+ struct buffer * buffer = (void *) base;
+ struct wld_exporter * exporter;
+
+ for (exporter = buffer->exporters; exporter; exporter = exporter->next)
+ {
+ if (exporter->export(exporter, &buffer->base, type, object))
+ return true;
+ }
+
+ return false;
+}
+
+EXPORT
+void wld_buffer_add_exporter(struct wld_buffer * base,
+ struct wld_exporter * exporter)
+{
+ struct buffer * buffer = (void *) base;
+
+ exporter->next = buffer->exporters;
+ buffer->exporters = exporter;
+}
+
+EXPORT
+void wld_buffer_add_destructor(struct wld_buffer * base,
+ struct wld_destructor * destructor)
+{
+ struct buffer * buffer = (void *) base;
+
+ destructor->next = buffer->destructors;
+ buffer->destructors = destructor;
+}
+
+EXPORT
+void wld_buffer_reference(struct wld_buffer * base)
+{
+ struct buffer * buffer = (void *) base;
+
+ ++buffer->references;
+}
+
+EXPORT
+void wld_buffer_unreference(struct wld_buffer * base)
+{
+ struct buffer * buffer = (void *) base;
+ struct wld_destructor * destructor, * next;
+
+ if (--buffer->references > 0)
+ return;
+
+ pixman_region32_fini(&buffer->base.damage);
+
+ for (destructor = buffer->destructors; destructor; destructor = next)
+ {
+ next = destructor->next;
+ destructor->destroy(destructor);
+ }
+
+ if (buffer->map_references > 0)
+ buffer->base.impl->unmap(buffer);
+
+ buffer->base.impl->destroy(buffer);
+}
+
diff --git a/src/wld/buffered_surface.c b/src/wld/buffered_surface.c
new file mode 100644
index 0000000..e3d9133
--- /dev/null
+++ b/src/wld/buffered_surface.c
@@ -0,0 +1,224 @@
+/* wld: buffered_surface.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wld-private.h"
+
+#include "interface/surface.h"
+IMPL(buffered_surface, wld_surface)
+
+struct buffer_entry
+{
+ struct buffer * buffer;
+ bool busy;
+};
+
+struct buffered_surface
+{
+ struct wld_surface base;
+
+ struct wld_context * context;
+ struct buffer_entry * entries, * back;
+ unsigned entries_size, entries_capacity;
+
+ struct buffer_socket * buffer_socket;
+
+ uint32_t width, height;
+ enum wld_format format;
+ uint32_t flags;
+};
+
+struct wld_surface * buffered_surface_create
+ (struct wld_context * context, uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags, struct buffer_socket * buffer_socket)
+{
+ struct buffered_surface * surface;
+
+ if (!(surface = malloc(sizeof *surface)))
+ return NULL;
+
+ surface_initialize(&surface->base, &wld_surface_impl);
+ surface->context = context;
+ surface->entries = NULL;
+ surface->back = NULL;
+ surface->entries_size = 0;
+ surface->entries_capacity = 0;
+ surface->buffer_socket = buffer_socket;
+ surface->width = width;
+ surface->height = height;
+ surface->format = format;
+ surface->flags = flags;
+
+ return &surface->base;
+}
+
+pixman_region32_t * surface_damage(struct wld_surface * base,
+ pixman_region32_t * new_damage)
+{
+ struct buffered_surface * surface = buffered_surface(base);
+ struct buffer * back_buffer;
+ unsigned index;
+
+ if (pixman_region32_not_empty(new_damage))
+ {
+ for (index = 0; index < surface->entries_size; ++index)
+ {
+ pixman_region32_union(&surface->entries[index].buffer->base.damage,
+ &surface->entries[index].buffer->base.damage,
+ new_damage);
+ }
+ }
+
+ if (!(back_buffer = surface_back(base)))
+ return NULL;
+
+ return &back_buffer->base.damage;
+}
+
+struct buffer * surface_back(struct wld_surface * base)
+{
+ struct buffered_surface * surface = buffered_surface(base);
+ unsigned index;
+
+ if (surface->back)
+ return surface->back->buffer;
+
+ /* The buffer socket may need to process any incoming buffer releases. */
+ if (surface->buffer_socket)
+ surface->buffer_socket->impl->process(surface->buffer_socket);
+
+ for (index = 0; index < surface->entries_size; ++index)
+ {
+ if (!surface->entries[index].busy)
+ {
+ surface->back = &surface->entries[index];
+ return surface->back->buffer;
+ }
+ }
+
+ /* If there are no free buffers, we need to allocate another one. */
+ struct buffer * buffer;
+
+ buffer = surface->context->impl->create_buffer
+ (surface->context, surface->width, surface->height,
+ surface->format, surface->flags);
+
+ if (!buffer)
+ goto error0;
+
+ if (surface->entries_size == surface->entries_capacity)
+ {
+ struct buffer_entry * new_entries;
+ size_t new_capacity = surface->entries_capacity * 2 + 1;
+
+ new_entries = realloc(surface->entries,
+ new_capacity * sizeof surface->entries[0]);
+
+ if (!new_entries)
+ goto error1;
+
+ surface->entries = new_entries;
+ surface->entries_capacity = new_capacity;
+ }
+
+ surface->back = &surface->entries[surface->entries_size++];
+ *surface->back = (struct buffer_entry) {
+ .buffer = buffer,
+ .busy = false
+ };
+
+ return buffer;
+
+ error1:
+ wld_buffer_unreference(&buffer->base);
+ error0:
+ return NULL;
+}
+
+struct buffer * surface_take(struct wld_surface * base)
+{
+ struct buffered_surface * surface = buffered_surface(base);
+ struct buffer * buffer;
+
+ if (!(buffer = surface_back(base)))
+ return NULL;
+
+ surface->back->busy = true;
+ surface->back = NULL;
+ pixman_region32_clear(&buffer->base.damage);
+
+ return buffer;
+}
+
+bool surface_release(struct wld_surface * base, struct buffer * buffer)
+{
+ struct buffered_surface * surface = buffered_surface(base);
+ unsigned index;
+
+ for (index = 0; index < surface->entries_size; ++index)
+ {
+ if (surface->entries[index].buffer == buffer)
+ {
+ surface->entries[index].busy = false;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool surface_swap(struct wld_surface * base)
+{
+ struct buffered_surface * surface = buffered_surface(base);
+ struct buffer * buffer;
+
+ if (!surface->buffer_socket)
+ return false;
+
+ if (!(buffer = surface_back(base)))
+ return false;
+
+ if (!surface->buffer_socket->impl->attach(surface->buffer_socket, buffer))
+ return false;
+
+ surface->back->busy = true;
+ surface->back = NULL;
+ pixman_region32_clear(&buffer->base.damage);
+
+ return true;
+}
+
+void surface_destroy(struct wld_surface * base)
+{
+ struct buffered_surface * surface = buffered_surface(base);
+ unsigned index;
+
+ if (surface->buffer_socket)
+ surface->buffer_socket->impl->destroy(surface->buffer_socket);
+
+ for (index = 0; index < surface->entries_size; ++index)
+ wld_buffer_unreference(&surface->entries[index].buffer->base);
+
+ free(surface->entries);
+ free(surface);
+}
+
diff --git a/src/wld/color.c b/src/wld/color.c
new file mode 100644
index 0000000..88e791a
--- /dev/null
+++ b/src/wld/color.c
@@ -0,0 +1,850 @@
+/* Adapted from xorg-server */
+
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#include "wld-private.h"
+
+#include <strings.h>
+
+struct named_color
+{
+ const char * name;
+ uint32_t color;
+};
+
+static const struct named_color named_colors[] = {
+ { "alice blue", 0xfff0f8ff },
+ { "AliceBlue", 0xfff0f8ff },
+ { "antique white", 0xfffaebd7 },
+ { "AntiqueWhite", 0xfffaebd7 },
+ { "AntiqueWhite1", 0xffffefdb },
+ { "AntiqueWhite2", 0xffeedfcc },
+ { "AntiqueWhite3", 0xffcdc0b0 },
+ { "AntiqueWhite4", 0xff8b8378 },
+ { "aquamarine", 0xff7fffd4 },
+ { "aquamarine1", 0xff7fffd4 },
+ { "aquamarine2", 0xff76eec6 },
+ { "aquamarine3", 0xff66cdaa },
+ { "aquamarine4", 0xff458b74 },
+ { "azure", 0xfff0ffff },
+ { "azure1", 0xfff0ffff },
+ { "azure2", 0xffe0eeee },
+ { "azure3", 0xffc1cdcd },
+ { "azure4", 0xff838b8b },
+ { "beige", 0xfff5f5dc },
+ { "bisque", 0xffffe4c4 },
+ { "bisque1", 0xffffe4c4 },
+ { "bisque2", 0xffeed5b7 },
+ { "bisque3", 0xffcdb79e },
+ { "bisque4", 0xff8b7d6b },
+ { "black", 0xff000000 },
+ { "blanched almond", 0xffffebcd },
+ { "BlanchedAlmond", 0xffffebcd },
+ { "blue", 0xff0000ff },
+ { "blue violet", 0xff8a2be2 },
+ { "blue1", 0xff0000ff },
+ { "blue2", 0xff0000ee },
+ { "blue3", 0xff0000cd },
+ { "blue4", 0xff00008b },
+ { "BlueViolet", 0xff8a2be2 },
+ { "brown", 0xffa52a2a },
+ { "brown1", 0xffff4040 },
+ { "brown2", 0xffee3b3b },
+ { "brown3", 0xffcd3333 },
+ { "brown4", 0xff8b2323 },
+ { "burlywood", 0xffdeb887 },
+ { "burlywood1", 0xffffd39b },
+ { "burlywood2", 0xffeec591 },
+ { "burlywood3", 0xffcdaa7d },
+ { "burlywood4", 0xff8b7355 },
+ { "cadet blue", 0xff5f9ea0 },
+ { "CadetBlue", 0xff5f9ea0 },
+ { "CadetBlue1", 0xff98f5ff },
+ { "CadetBlue2", 0xff8ee5ee },
+ { "CadetBlue3", 0xff7ac5cd },
+ { "CadetBlue4", 0xff53868b },
+ { "chartreuse", 0xff7fff00 },
+ { "chartreuse1", 0xff7fff00 },
+ { "chartreuse2", 0xff76ee00 },
+ { "chartreuse3", 0xff66cd00 },
+ { "chartreuse4", 0xff458b00 },
+ { "chocolate", 0xffd2691e },
+ { "chocolate1", 0xffff7f24 },
+ { "chocolate2", 0xffee7621 },
+ { "chocolate3", 0xffcd661d },
+ { "chocolate4", 0xff8b4513 },
+ { "coral", 0xffff7f50 },
+ { "coral1", 0xffff7256 },
+ { "coral2", 0xffee6a50 },
+ { "coral3", 0xffcd5b45 },
+ { "coral4", 0xff8b3e2f },
+ { "cornflower blue", 0xff6495ed },
+ { "CornflowerBlue", 0xff6495ed },
+ { "cornsilk", 0xfffff8dc },
+ { "cornsilk1", 0xfffff8dc },
+ { "cornsilk2", 0xffeee8cd },
+ { "cornsilk3", 0xffcdc8b1 },
+ { "cornsilk4", 0xff8b8878 },
+ { "cyan", 0xff00ffff },
+ { "cyan1", 0xff00ffff },
+ { "cyan2", 0xff00eeee },
+ { "cyan3", 0xff00cdcd },
+ { "cyan4", 0xff008b8b },
+ { "dark blue", 0xff00008b },
+ { "dark cyan", 0xff008b8b },
+ { "dark goldenrod", 0xffb8860b },
+ { "dark gray", 0xffa9a9a9 },
+ { "dark green", 0xff006400 },
+ { "dark grey", 0xffa9a9a9 },
+ { "dark khaki", 0xffbdb76b },
+ { "dark magenta", 0xff8b008b },
+ { "dark olive green", 0xff556b2f },
+ { "dark orange", 0xffff8c00 },
+ { "dark orchid", 0xff9932cc },
+ { "dark red", 0xff8b0000 },
+ { "dark salmon", 0xffe9967a },
+ { "dark sea green", 0xff8fbc8f },
+ { "dark slate blue", 0xff483d8b },
+ { "dark slate gray", 0xff2f4f4f },
+ { "dark slate grey", 0xff2f4f4f },
+ { "dark turquoise", 0xff00ced1 },
+ { "dark violet", 0xff9400d3 },
+ { "DarkBlue", 0xff00008b },
+ { "DarkCyan", 0xff008b8b },
+ { "DarkGoldenrod", 0xffb8860b },
+ { "DarkGoldenrod1", 0xffffb90f },
+ { "DarkGoldenrod2", 0xffeead0e },
+ { "DarkGoldenrod3", 0xffcd950c },
+ { "DarkGoldenrod4", 0xff8b6508 },
+ { "DarkGray", 0xffa9a9a9 },
+ { "DarkGreen", 0xff006400 },
+ { "DarkGrey", 0xffa9a9a9 },
+ { "DarkKhaki", 0xffbdb76b },
+ { "DarkMagenta", 0xff8b008b },
+ { "DarkOliveGreen", 0xff556b2f },
+ { "DarkOliveGreen1", 0xffcaff70 },
+ { "DarkOliveGreen2", 0xffbcee68 },
+ { "DarkOliveGreen3", 0xffa2cd5a },
+ { "DarkOliveGreen4", 0xff6e8b3d },
+ { "DarkOrange", 0xffff8c00 },
+ { "DarkOrange1", 0xffff7f00 },
+ { "DarkOrange2", 0xffee7600 },
+ { "DarkOrange3", 0xffcd6600 },
+ { "DarkOrange4", 0xff8b4500 },
+ { "DarkOrchid", 0xff9932cc },
+ { "DarkOrchid1", 0xffbf3eff },
+ { "DarkOrchid2", 0xffb23aee },
+ { "DarkOrchid3", 0xff9a32cd },
+ { "DarkOrchid4", 0xff68228b },
+ { "DarkRed", 0xff8b0000 },
+ { "DarkSalmon", 0xffe9967a },
+ { "DarkSeaGreen", 0xff8fbc8f },
+ { "DarkSeaGreen1", 0xffc1ffc1 },
+ { "DarkSeaGreen2", 0xffb4eeb4 },
+ { "DarkSeaGreen3", 0xff9bcd9b },
+ { "DarkSeaGreen4", 0xff698b69 },
+ { "DarkSlateBlue", 0xff483d8b },
+ { "DarkSlateGray", 0xff2f4f4f },
+ { "DarkSlateGray1", 0xff97ffff },
+ { "DarkSlateGray2", 0xff8deeee },
+ { "DarkSlateGray3", 0xff79cdcd },
+ { "DarkSlateGray4", 0xff528b8b },
+ { "DarkSlateGrey", 0xff2f4f4f },
+ { "DarkTurquoise", 0xff00ced1 },
+ { "DarkViolet", 0xff9400d3 },
+ { "deep pink", 0xffff1493 },
+ { "deep sky blue", 0xff00bfff },
+ { "DeepPink", 0xffff1493 },
+ { "DeepPink1", 0xffff1493 },
+ { "DeepPink2", 0xffee1289 },
+ { "DeepPink3", 0xffcd1076 },
+ { "DeepPink4", 0xff8b0a50 },
+ { "DeepSkyBlue", 0xff00bfff },
+ { "DeepSkyBlue1", 0xff00bfff },
+ { "DeepSkyBlue2", 0xff00b2ee },
+ { "DeepSkyBlue3", 0xff009acd },
+ { "DeepSkyBlue4", 0xff00688b },
+ { "dim gray", 0xff696969 },
+ { "dim grey", 0xff696969 },
+ { "DimGray", 0xff696969 },
+ { "DimGrey", 0xff696969 },
+ { "dodger blue", 0xff1e90ff },
+ { "DodgerBlue", 0xff1e90ff },
+ { "DodgerBlue1", 0xff1e90ff },
+ { "DodgerBlue2", 0xff1c86ee },
+ { "DodgerBlue3", 0xff1874cd },
+ { "DodgerBlue4", 0xff104e8b },
+ { "firebrick", 0xffb22222 },
+ { "firebrick1", 0xffff3030 },
+ { "firebrick2", 0xffee2c2c },
+ { "firebrick3", 0xffcd2626 },
+ { "firebrick4", 0xff8b1a1a },
+ { "floral white", 0xfffffaf0 },
+ { "FloralWhite", 0xfffffaf0 },
+ { "forest green", 0xff228b22 },
+ { "ForestGreen", 0xff228b22 },
+ { "gainsboro", 0xffdcdcdc },
+ { "ghost white", 0xfff8f8ff },
+ { "GhostWhite", 0xfff8f8ff },
+ { "gold", 0xffffd700 },
+ { "gold1", 0xffffd700 },
+ { "gold2", 0xffeec900 },
+ { "gold3", 0xffcdad00 },
+ { "gold4", 0xff8b7500 },
+ { "goldenrod", 0xffdaa520 },
+ { "goldenrod1", 0xffffc125 },
+ { "goldenrod2", 0xffeeb422 },
+ { "goldenrod3", 0xffcd9b1d },
+ { "goldenrod4", 0xff8b6914 },
+ { "gray", 0xffbebebe },
+ { "gray0", 0xff000000 },
+ { "gray1", 0xff030303 },
+ { "gray10", 0xff1a1a1a },
+ { "gray100", 0xffffffff },
+ { "gray11", 0xff1c1c1c },
+ { "gray12", 0xff1f1f1f },
+ { "gray13", 0xff212121 },
+ { "gray14", 0xff242424 },
+ { "gray15", 0xff262626 },
+ { "gray16", 0xff292929 },
+ { "gray17", 0xff2b2b2b },
+ { "gray18", 0xff2e2e2e },
+ { "gray19", 0xff303030 },
+ { "gray2", 0xff050505 },
+ { "gray20", 0xff333333 },
+ { "gray21", 0xff363636 },
+ { "gray22", 0xff383838 },
+ { "gray23", 0xff3b3b3b },
+ { "gray24", 0xff3d3d3d },
+ { "gray25", 0xff404040 },
+ { "gray26", 0xff424242 },
+ { "gray27", 0xff454545 },
+ { "gray28", 0xff474747 },
+ { "gray29", 0xff4a4a4a },
+ { "gray3", 0xff080808 },
+ { "gray30", 0xff4d4d4d },
+ { "gray31", 0xff4f4f4f },
+ { "gray32", 0xff525252 },
+ { "gray33", 0xff545454 },
+ { "gray34", 0xff575757 },
+ { "gray35", 0xff595959 },
+ { "gray36", 0xff5c5c5c },
+ { "gray37", 0xff5e5e5e },
+ { "gray38", 0xff616161 },
+ { "gray39", 0xff636363 },
+ { "gray4", 0xff0a0a0a },
+ { "gray40", 0xff666666 },
+ { "gray41", 0xff696969 },
+ { "gray42", 0xff6b6b6b },
+ { "gray43", 0xff6e6e6e },
+ { "gray44", 0xff707070 },
+ { "gray45", 0xff737373 },
+ { "gray46", 0xff757575 },
+ { "gray47", 0xff787878 },
+ { "gray48", 0xff7a7a7a },
+ { "gray49", 0xff7d7d7d },
+ { "gray5", 0xff0d0d0d },
+ { "gray50", 0xff7f7f7f },
+ { "gray51", 0xff828282 },
+ { "gray52", 0xff858585 },
+ { "gray53", 0xff878787 },
+ { "gray54", 0xff8a8a8a },
+ { "gray55", 0xff8c8c8c },
+ { "gray56", 0xff8f8f8f },
+ { "gray57", 0xff919191 },
+ { "gray58", 0xff949494 },
+ { "gray59", 0xff969696 },
+ { "gray6", 0xff0f0f0f },
+ { "gray60", 0xff999999 },
+ { "gray61", 0xff9c9c9c },
+ { "gray62", 0xff9e9e9e },
+ { "gray63", 0xffa1a1a1 },
+ { "gray64", 0xffa3a3a3 },
+ { "gray65", 0xffa6a6a6 },
+ { "gray66", 0xffa8a8a8 },
+ { "gray67", 0xffababab },
+ { "gray68", 0xffadadad },
+ { "gray69", 0xffb0b0b0 },
+ { "gray7", 0xff121212 },
+ { "gray70", 0xffb3b3b3 },
+ { "gray71", 0xffb5b5b5 },
+ { "gray72", 0xffb8b8b8 },
+ { "gray73", 0xffbababa },
+ { "gray74", 0xffbdbdbd },
+ { "gray75", 0xffbfbfbf },
+ { "gray76", 0xffc2c2c2 },
+ { "gray77", 0xffc4c4c4 },
+ { "gray78", 0xffc7c7c7 },
+ { "gray79", 0xffc9c9c9 },
+ { "gray8", 0xff141414 },
+ { "gray80", 0xffcccccc },
+ { "gray81", 0xffcfcfcf },
+ { "gray82", 0xffd1d1d1 },
+ { "gray83", 0xffd4d4d4 },
+ { "gray84", 0xffd6d6d6 },
+ { "gray85", 0xffd9d9d9 },
+ { "gray86", 0xffdbdbdb },
+ { "gray87", 0xffdedede },
+ { "gray88", 0xffe0e0e0 },
+ { "gray89", 0xffe3e3e3 },
+ { "gray9", 0xff171717 },
+ { "gray90", 0xffe5e5e5 },
+ { "gray91", 0xffe8e8e8 },
+ { "gray92", 0xffebebeb },
+ { "gray93", 0xffededed },
+ { "gray94", 0xfff0f0f0 },
+ { "gray95", 0xfff2f2f2 },
+ { "gray96", 0xfff5f5f5 },
+ { "gray97", 0xfff7f7f7 },
+ { "gray98", 0xfffafafa },
+ { "gray99", 0xfffcfcfc },
+ { "green", 0xff00ff00 },
+ { "green yellow", 0xffadff2f },
+ { "green1", 0xff00ff00 },
+ { "green2", 0xff00ee00 },
+ { "green3", 0xff00cd00 },
+ { "green4", 0xff008b00 },
+ { "GreenYellow", 0xffadff2f },
+ { "grey", 0xffbebebe },
+ { "grey0", 0xff000000 },
+ { "grey1", 0xff030303 },
+ { "grey10", 0xff1a1a1a },
+ { "grey100", 0xffffffff },
+ { "grey11", 0xff1c1c1c },
+ { "grey12", 0xff1f1f1f },
+ { "grey13", 0xff212121 },
+ { "grey14", 0xff242424 },
+ { "grey15", 0xff262626 },
+ { "grey16", 0xff292929 },
+ { "grey17", 0xff2b2b2b },
+ { "grey18", 0xff2e2e2e },
+ { "grey19", 0xff303030 },
+ { "grey2", 0xff050505 },
+ { "grey20", 0xff333333 },
+ { "grey21", 0xff363636 },
+ { "grey22", 0xff383838 },
+ { "grey23", 0xff3b3b3b },
+ { "grey24", 0xff3d3d3d },
+ { "grey25", 0xff404040 },
+ { "grey26", 0xff424242 },
+ { "grey27", 0xff454545 },
+ { "grey28", 0xff474747 },
+ { "grey29", 0xff4a4a4a },
+ { "grey3", 0xff080808 },
+ { "grey30", 0xff4d4d4d },
+ { "grey31", 0xff4f4f4f },
+ { "grey32", 0xff525252 },
+ { "grey33", 0xff545454 },
+ { "grey34", 0xff575757 },
+ { "grey35", 0xff595959 },
+ { "grey36", 0xff5c5c5c },
+ { "grey37", 0xff5e5e5e },
+ { "grey38", 0xff616161 },
+ { "grey39", 0xff636363 },
+ { "grey4", 0xff0a0a0a },
+ { "grey40", 0xff666666 },
+ { "grey41", 0xff696969 },
+ { "grey42", 0xff6b6b6b },
+ { "grey43", 0xff6e6e6e },
+ { "grey44", 0xff707070 },
+ { "grey45", 0xff737373 },
+ { "grey46", 0xff757575 },
+ { "grey47", 0xff787878 },
+ { "grey48", 0xff7a7a7a },
+ { "grey49", 0xff7d7d7d },
+ { "grey5", 0xff0d0d0d },
+ { "grey50", 0xff7f7f7f },
+ { "grey51", 0xff828282 },
+ { "grey52", 0xff858585 },
+ { "grey53", 0xff878787 },
+ { "grey54", 0xff8a8a8a },
+ { "grey55", 0xff8c8c8c },
+ { "grey56", 0xff8f8f8f },
+ { "grey57", 0xff919191 },
+ { "grey58", 0xff949494 },
+ { "grey59", 0xff969696 },
+ { "grey6", 0xff0f0f0f },
+ { "grey60", 0xff999999 },
+ { "grey61", 0xff9c9c9c },
+ { "grey62", 0xff9e9e9e },
+ { "grey63", 0xffa1a1a1 },
+ { "grey64", 0xffa3a3a3 },
+ { "grey65", 0xffa6a6a6 },
+ { "grey66", 0xffa8a8a8 },
+ { "grey67", 0xffababab },
+ { "grey68", 0xffadadad },
+ { "grey69", 0xffb0b0b0 },
+ { "grey7", 0xff121212 },
+ { "grey70", 0xffb3b3b3 },
+ { "grey71", 0xffb5b5b5 },
+ { "grey72", 0xffb8b8b8 },
+ { "grey73", 0xffbababa },
+ { "grey74", 0xffbdbdbd },
+ { "grey75", 0xffbfbfbf },
+ { "grey76", 0xffc2c2c2 },
+ { "grey77", 0xffc4c4c4 },
+ { "grey78", 0xffc7c7c7 },
+ { "grey79", 0xffc9c9c9 },
+ { "grey8", 0xff141414 },
+ { "grey80", 0xffcccccc },
+ { "grey81", 0xffcfcfcf },
+ { "grey82", 0xffd1d1d1 },
+ { "grey83", 0xffd4d4d4 },
+ { "grey84", 0xffd6d6d6 },
+ { "grey85", 0xffd9d9d9 },
+ { "grey86", 0xffdbdbdb },
+ { "grey87", 0xffdedede },
+ { "grey88", 0xffe0e0e0 },
+ { "grey89", 0xffe3e3e3 },
+ { "grey9", 0xff171717 },
+ { "grey90", 0xffe5e5e5 },
+ { "grey91", 0xffe8e8e8 },
+ { "grey92", 0xffebebeb },
+ { "grey93", 0xffededed },
+ { "grey94", 0xfff0f0f0 },
+ { "grey95", 0xfff2f2f2 },
+ { "grey96", 0xfff5f5f5 },
+ { "grey97", 0xfff7f7f7 },
+ { "grey98", 0xfffafafa },
+ { "grey99", 0xfffcfcfc },
+ { "honeydew", 0xfff0fff0 },
+ { "honeydew1", 0xfff0fff0 },
+ { "honeydew2", 0xffe0eee0 },
+ { "honeydew3", 0xffc1cdc1 },
+ { "honeydew4", 0xff838b83 },
+ { "hot pink", 0xffff69b4 },
+ { "HotPink", 0xffff69b4 },
+ { "HotPink1", 0xffff6eb4 },
+ { "HotPink2", 0xffee6aa7 },
+ { "HotPink3", 0xffcd6090 },
+ { "HotPink4", 0xff8b3a62 },
+ { "indian red", 0xffcd5c5c },
+ { "IndianRed", 0xffcd5c5c },
+ { "IndianRed1", 0xffff6a6a },
+ { "IndianRed2", 0xffee6363 },
+ { "IndianRed3", 0xffcd5555 },
+ { "IndianRed4", 0xff8b3a3a },
+ { "ivory", 0xfffffff0 },
+ { "ivory1", 0xfffffff0 },
+ { "ivory2", 0xffeeeee0 },
+ { "ivory3", 0xffcdcdc1 },
+ { "ivory4", 0xff8b8b83 },
+ { "khaki", 0xfff0e68c },
+ { "khaki1", 0xfffff68f },
+ { "khaki2", 0xffeee685 },
+ { "khaki3", 0xffcdc673 },
+ { "khaki4", 0xff8b864e },
+ { "lavender", 0xffe6e6fa },
+ { "lavender blush", 0xfffff0f5 },
+ { "LavenderBlush", 0xfffff0f5 },
+ { "LavenderBlush1", 0xfffff0f5 },
+ { "LavenderBlush2", 0xffeee0e5 },
+ { "LavenderBlush3", 0xffcdc1c5 },
+ { "LavenderBlush4", 0xff8b8386 },
+ { "lawn green", 0xff7cfc00 },
+ { "LawnGreen", 0xff7cfc00 },
+ { "lemon chiffon", 0xfffffacd },
+ { "LemonChiffon", 0xfffffacd },
+ { "LemonChiffon1", 0xfffffacd },
+ { "LemonChiffon2", 0xffeee9bf },
+ { "LemonChiffon3", 0xffcdc9a5 },
+ { "LemonChiffon4", 0xff8b8970 },
+ { "light blue", 0xffadd8e6 },
+ { "light coral", 0xfff08080 },
+ { "light cyan", 0xffe0ffff },
+ { "light goldenrod", 0xffeedd82 },
+ { "light goldenrod yellow", 0xfffafad2 },
+ { "light gray", 0xffd3d3d3 },
+ { "light green", 0xff90ee90 },
+ { "light grey", 0xffd3d3d3 },
+ { "light pink", 0xffffb6c1 },
+ { "light salmon", 0xffffa07a },
+ { "light sea green", 0xff20b2aa },
+ { "light sky blue", 0xff87cefa },
+ { "light slate blue", 0xff8470ff },
+ { "light slate gray", 0xff778899 },
+ { "light slate grey", 0xff778899 },
+ { "light steel blue", 0xffb0c4de },
+ { "light yellow", 0xffffffe0 },
+ { "LightBlue", 0xffadd8e6 },
+ { "LightBlue1", 0xffbfefff },
+ { "LightBlue2", 0xffb2dfee },
+ { "LightBlue3", 0xff9ac0cd },
+ { "LightBlue4", 0xff68838b },
+ { "LightCoral", 0xfff08080 },
+ { "LightCyan", 0xffe0ffff },
+ { "LightCyan1", 0xffe0ffff },
+ { "LightCyan2", 0xffd1eeee },
+ { "LightCyan3", 0xffb4cdcd },
+ { "LightCyan4", 0xff7a8b8b },
+ { "LightGoldenrod", 0xffeedd82 },
+ { "LightGoldenrod1", 0xffffec8b },
+ { "LightGoldenrod2", 0xffeedc82 },
+ { "LightGoldenrod3", 0xffcdbe70 },
+ { "LightGoldenrod4", 0xff8b814c },
+ { "LightGoldenrodYellow", 0xfffafad2 },
+ { "LightGray", 0xffd3d3d3 },
+ { "LightGreen", 0xff90ee90 },
+ { "LightGrey", 0xffd3d3d3 },
+ { "LightPink", 0xffffb6c1 },
+ { "LightPink1", 0xffffaeb9 },
+ { "LightPink2", 0xffeea2ad },
+ { "LightPink3", 0xffcd8c95 },
+ { "LightPink4", 0xff8b5f65 },
+ { "LightSalmon", 0xffffa07a },
+ { "LightSalmon1", 0xffffa07a },
+ { "LightSalmon2", 0xffee9572 },
+ { "LightSalmon3", 0xffcd8162 },
+ { "LightSalmon4", 0xff8b5742 },
+ { "LightSeaGreen", 0xff20b2aa },
+ { "LightSkyBlue", 0xff87cefa },
+ { "LightSkyBlue1", 0xffb0e2ff },
+ { "LightSkyBlue2", 0xffa4d3ee },
+ { "LightSkyBlue3", 0xff8db6cd },
+ { "LightSkyBlue4", 0xff607b8b },
+ { "LightSlateBlue", 0xff8470ff },
+ { "LightSlateGray", 0xff778899 },
+ { "LightSlateGrey", 0xff778899 },
+ { "LightSteelBlue", 0xffb0c4de },
+ { "LightSteelBlue1", 0xffcae1ff },
+ { "LightSteelBlue2", 0xffbcd2ee },
+ { "LightSteelBlue3", 0xffa2b5cd },
+ { "LightSteelBlue4", 0xff6e7b8b },
+ { "LightYellow", 0xffffffe0 },
+ { "LightYellow1", 0xffffffe0 },
+ { "LightYellow2", 0xffeeeed1 },
+ { "LightYellow3", 0xffcdcdb4 },
+ { "LightYellow4", 0xff8b8b7a },
+ { "lime green", 0xff32cd32 },
+ { "LimeGreen", 0xff32cd32 },
+ { "linen", 0xfffaf0e6 },
+ { "magenta", 0xffff00ff },
+ { "magenta1", 0xffff00ff },
+ { "magenta2", 0xffee00ee },
+ { "magenta3", 0xffcd00cd },
+ { "magenta4", 0xff8b008b },
+ { "maroon", 0xffb03060 },
+ { "maroon1", 0xffff34b3 },
+ { "maroon2", 0xffee30a7 },
+ { "maroon3", 0xffcd2990 },
+ { "maroon4", 0xff8b1c62 },
+ { "medium aquamarine", 0xff66cdaa },
+ { "medium blue", 0xff0000cd },
+ { "medium orchid", 0xffba55d3 },
+ { "medium purple", 0xff9370db },
+ { "medium sea green", 0xff3cb371 },
+ { "medium slate blue", 0xff7b68ee },
+ { "medium spring green", 0xff00fa9a },
+ { "medium turquoise", 0xff48d1cc },
+ { "medium violet red", 0xffc71585 },
+ { "MediumAquamarine", 0xff66cdaa },
+ { "MediumBlue", 0xff0000cd },
+ { "MediumOrchid", 0xffba55d3 },
+ { "MediumOrchid1", 0xffe066ff },
+ { "MediumOrchid2", 0xffd15fee },
+ { "MediumOrchid3", 0xffb452cd },
+ { "MediumOrchid4", 0xff7a378b },
+ { "MediumPurple", 0xff9370db },
+ { "MediumPurple1", 0xffab82ff },
+ { "MediumPurple2", 0xff9f79ee },
+ { "MediumPurple3", 0xff8968cd },
+ { "MediumPurple4", 0xff5d478b },
+ { "MediumSeaGreen", 0xff3cb371 },
+ { "MediumSlateBlue", 0xff7b68ee },
+ { "MediumSpringGreen", 0xff00fa9a },
+ { "MediumTurquoise", 0xff48d1cc },
+ { "MediumVioletRed", 0xffc71585 },
+ { "midnight blue", 0xff191970 },
+ { "MidnightBlue", 0xff191970 },
+ { "mint cream", 0xfff5fffa },
+ { "MintCream", 0xfff5fffa },
+ { "misty rose", 0xffffe4e1 },
+ { "MistyRose", 0xffffe4e1 },
+ { "MistyRose1", 0xffffe4e1 },
+ { "MistyRose2", 0xffeed5d2 },
+ { "MistyRose3", 0xffcdb7b5 },
+ { "MistyRose4", 0xff8b7d7b },
+ { "moccasin", 0xffffe4b5 },
+ { "navajo white", 0xffffdead },
+ { "NavajoWhite", 0xffffdead },
+ { "NavajoWhite1", 0xffffdead },
+ { "NavajoWhite2", 0xffeecfa1 },
+ { "NavajoWhite3", 0xffcdb38b },
+ { "NavajoWhite4", 0xff8b795e },
+ { "navy", 0xff000080 },
+ { "navy blue", 0xff000080 },
+ { "NavyBlue", 0xff000080 },
+ { "old lace", 0xfffdf5e6 },
+ { "OldLace", 0xfffdf5e6 },
+ { "olive drab", 0xff6b8e23 },
+ { "OliveDrab", 0xff6b8e23 },
+ { "OliveDrab1", 0xffc0ff3e },
+ { "OliveDrab2", 0xffb3ee3a },
+ { "OliveDrab3", 0xff9acd32 },
+ { "OliveDrab4", 0xff698b22 },
+ { "orange", 0xffffa500 },
+ { "orange red", 0xffff4500 },
+ { "orange1", 0xffffa500 },
+ { "orange2", 0xffee9a00 },
+ { "orange3", 0xffcd8500 },
+ { "orange4", 0xff8b5a00 },
+ { "OrangeRed", 0xffff4500 },
+ { "OrangeRed1", 0xffff4500 },
+ { "OrangeRed2", 0xffee4000 },
+ { "OrangeRed3", 0xffcd3700 },
+ { "OrangeRed4", 0xff8b2500 },
+ { "orchid", 0xffda70d6 },
+ { "orchid1", 0xffff83fa },
+ { "orchid2", 0xffee7ae9 },
+ { "orchid3", 0xffcd69c9 },
+ { "orchid4", 0xff8b4789 },
+ { "pale goldenrod", 0xffeee8aa },
+ { "pale green", 0xff98fb98 },
+ { "pale turquoise", 0xffafeeee },
+ { "pale violet red", 0xffdb7093 },
+ { "PaleGoldenrod", 0xffeee8aa },
+ { "PaleGreen", 0xff98fb98 },
+ { "PaleGreen1", 0xff9aff9a },
+ { "PaleGreen2", 0xff90ee90 },
+ { "PaleGreen3", 0xff7ccd7c },
+ { "PaleGreen4", 0xff548b54 },
+ { "PaleTurquoise", 0xffafeeee },
+ { "PaleTurquoise1", 0xffbbffff },
+ { "PaleTurquoise2", 0xffaeeeee },
+ { "PaleTurquoise3", 0xff96cdcd },
+ { "PaleTurquoise4", 0xff668b8b },
+ { "PaleVioletRed", 0xffdb7093 },
+ { "PaleVioletRed1", 0xffff82ab },
+ { "PaleVioletRed2", 0xffee799f },
+ { "PaleVioletRed3", 0xffcd6889 },
+ { "PaleVioletRed4", 0xff8b475d },
+ { "papaya whip", 0xffffefd5 },
+ { "PapayaWhip", 0xffffefd5 },
+ { "peach puff", 0xffffdab9 },
+ { "PeachPuff", 0xffffdab9 },
+ { "PeachPuff1", 0xffffdab9 },
+ { "PeachPuff2", 0xffeecbad },
+ { "PeachPuff3", 0xffcdaf95 },
+ { "PeachPuff4", 0xff8b7765 },
+ { "peru", 0xffcd853f },
+ { "pink", 0xffffc0cb },
+ { "pink1", 0xffffb5c5 },
+ { "pink2", 0xffeea9b8 },
+ { "pink3", 0xffcd919e },
+ { "pink4", 0xff8b636c },
+ { "plum", 0xffdda0dd },
+ { "plum1", 0xffffbbff },
+ { "plum2", 0xffeeaeee },
+ { "plum3", 0xffcd96cd },
+ { "plum4", 0xff8b668b },
+ { "powder blue", 0xffb0e0e6 },
+ { "PowderBlue", 0xffb0e0e6 },
+ { "purple", 0xffa020f0 },
+ { "purple1", 0xff9b30ff },
+ { "purple2", 0xff912cee },
+ { "purple3", 0xff7d26cd },
+ { "purple4", 0xff551a8b },
+ { "red", 0xffff0000 },
+ { "red1", 0xffff0000 },
+ { "red2", 0xffee0000 },
+ { "red3", 0xffcd0000 },
+ { "red4", 0xff8b0000 },
+ { "rosy brown", 0xffbc8f8f },
+ { "RosyBrown", 0xffbc8f8f },
+ { "RosyBrown1", 0xffffc1c1 },
+ { "RosyBrown2", 0xffeeb4b4 },
+ { "RosyBrown3", 0xffcd9b9b },
+ { "RosyBrown4", 0xff8b6969 },
+ { "royal blue", 0xff4169e1 },
+ { "RoyalBlue", 0xff4169e1 },
+ { "RoyalBlue1", 0xff4876ff },
+ { "RoyalBlue2", 0xff436eee },
+ { "RoyalBlue3", 0xff3a5fcd },
+ { "RoyalBlue4", 0xff27408b },
+ { "saddle brown", 0xff8b4513 },
+ { "SaddleBrown", 0xff8b4513 },
+ { "salmon", 0xfffa8072 },
+ { "salmon1", 0xffff8c69 },
+ { "salmon2", 0xffee8262 },
+ { "salmon3", 0xffcd7054 },
+ { "salmon4", 0xff8b4c39 },
+ { "sandy brown", 0xfff4a460 },
+ { "SandyBrown", 0xfff4a460 },
+ { "sea green", 0xff2e8b57 },
+ { "SeaGreen", 0xff2e8b57 },
+ { "SeaGreen1", 0xff54ff9f },
+ { "SeaGreen2", 0xff4eee94 },
+ { "SeaGreen3", 0xff43cd80 },
+ { "SeaGreen4", 0xff2e8b57 },
+ { "seashell", 0xfffff5ee },
+ { "seashell1", 0xfffff5ee },
+ { "seashell2", 0xffeee5de },
+ { "seashell3", 0xffcdc5bf },
+ { "seashell4", 0xff8b8682 },
+ { "sienna", 0xffa0522d },
+ { "sienna1", 0xffff8247 },
+ { "sienna2", 0xffee7942 },
+ { "sienna3", 0xffcd6839 },
+ { "sienna4", 0xff8b4726 },
+ { "sky blue", 0xff87ceeb },
+ { "SkyBlue", 0xff87ceeb },
+ { "SkyBlue1", 0xff87ceff },
+ { "SkyBlue2", 0xff7ec0ee },
+ { "SkyBlue3", 0xff6ca6cd },
+ { "SkyBlue4", 0xff4a708b },
+ { "slate blue", 0xff6a5acd },
+ { "slate gray", 0xff708090 },
+ { "slate grey", 0xff708090 },
+ { "SlateBlue", 0xff6a5acd },
+ { "SlateBlue1", 0xff836fff },
+ { "SlateBlue2", 0xff7a67ee },
+ { "SlateBlue3", 0xff6959cd },
+ { "SlateBlue4", 0xff473c8b },
+ { "SlateGray", 0xff708090 },
+ { "SlateGray1", 0xffc6e2ff },
+ { "SlateGray2", 0xffb9d3ee },
+ { "SlateGray3", 0xff9fb6cd },
+ { "SlateGray4", 0xff6c7b8b },
+ { "SlateGrey", 0xff708090 },
+ { "snow", 0xfffffafa },
+ { "snow1", 0xfffffafa },
+ { "snow2", 0xffeee9e9 },
+ { "snow3", 0xffcdc9c9 },
+ { "snow4", 0xff8b8989 },
+ { "spring green", 0xff00ff7f },
+ { "SpringGreen", 0xff00ff7f },
+ { "SpringGreen1", 0xff00ff7f },
+ { "SpringGreen2", 0xff00ee76 },
+ { "SpringGreen3", 0xff00cd66 },
+ { "SpringGreen4", 0xff008b45 },
+ { "steel blue", 0xff4682b4 },
+ { "SteelBlue", 0xff4682b4 },
+ { "SteelBlue1", 0xff63b8ff },
+ { "SteelBlue2", 0xff5cacee },
+ { "SteelBlue3", 0xff4f94cd },
+ { "SteelBlue4", 0xff36648b },
+ { "tan", 0xffd2b48c },
+ { "tan1", 0xffffa54f },
+ { "tan2", 0xffee9a49 },
+ { "tan3", 0xffcd853f },
+ { "tan4", 0xff8b5a2b },
+ { "thistle", 0xffd8bfd8 },
+ { "thistle1", 0xffffe1ff },
+ { "thistle2", 0xffeed2ee },
+ { "thistle3", 0xffcdb5cd },
+ { "thistle4", 0xff8b7b8b },
+ { "tomato", 0xffff6347 },
+ { "tomato1", 0xffff6347 },
+ { "tomato2", 0xffee5c42 },
+ { "tomato3", 0xffcd4f39 },
+ { "tomato4", 0xff8b3626 },
+ { "turquoise", 0xff40e0d0 },
+ { "turquoise1", 0xff00f5ff },
+ { "turquoise2", 0xff00e5ee },
+ { "turquoise3", 0xff00c5cd },
+ { "turquoise4", 0xff00868b },
+ { "violet", 0xffee82ee },
+ { "violet red", 0xffd02090 },
+ { "VioletRed", 0xffd02090 },
+ { "VioletRed1", 0xffff3e96 },
+ { "VioletRed2", 0xffee3a8c },
+ { "VioletRed3", 0xffcd3278 },
+ { "VioletRed4", 0xff8b2252 },
+ { "wheat", 0xfff5deb3 },
+ { "wheat1", 0xffffe7ba },
+ { "wheat2", 0xffeed8ae },
+ { "wheat3", 0xffcdba96 },
+ { "wheat4", 0xff8b7e66 },
+ { "white", 0xffffffff },
+ { "white smoke", 0xfff5f5f5 },
+ { "WhiteSmoke", 0xfff5f5f5 },
+ { "yellow", 0xffffff00 },
+ { "yellow green", 0xff9acd32 },
+ { "yellow1", 0xffffff00 },
+ { "yellow2", 0xffeeee00 },
+ { "yellow3", 0xffcdcd00 },
+ { "yellow4", 0xff8b8b00 },
+ { "YellowGreen", 0xff9acd32 }
+};
+
+EXPORT
+bool wld_lookup_named_color(const char * name, uint32_t * color)
+{
+ char * end;
+ int low = 0, mid, high = ARRAY_LENGTH(named_colors);
+ int r;
+
+ if (name[0] == '#' && name[1] != '\0')
+ {
+ *color = strtoul(name + 1, &end, 16);
+
+ /* Set alpha channel to opaque. */
+ *color |= 0xff << 24;
+
+ if (*end == '\0')
+ return true;
+ }
+
+ while (low <= high)
+ {
+ mid = (low + high) / 2;
+ r = strcasecmp(named_colors[mid].name, name);
+
+ if (r == 0)
+ {
+ *color = named_colors[mid].color;
+ return true;
+ }
+ if (r < 0)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ return false;
+}
+
diff --git a/src/wld/common.mk b/src/wld/common.mk
new file mode 100644
index 0000000..480ec90
--- /dev/null
+++ b/src/wld/common.mk
@@ -0,0 +1,11 @@
+# wld: common.mk
+
+.deps/$(dir): | .deps
+ @mkdir "$@"
+
+$(dir)/%.o: $(dir)/%.c | .deps/$(dir)
+ $(compile) $(WLD_PACKAGE_CFLAGS)
+
+$(dir)/%.lo: $(dir)/%.c | .deps/$(dir)
+ $(compile) $(WLD_PACKAGE_CFLAGS) -fPIC
+
diff --git a/src/wld/config.mk b/src/wld/config.mk
new file mode 100644
index 0000000..8f3ee29
--- /dev/null
+++ b/src/wld/config.mk
@@ -0,0 +1,20 @@
+# wld: config.mk
+
+CC = gcc
+CFLAGS = -pipe
+
+ENABLE_DEBUG = 1
+ENABLE_STATIC = 1
+ENABLE_SHARED = 0
+
+ENABLE_PIXMAN = 1
+ENABLE_DRM = 1
+ENABLE_WAYLAND = 1
+
+DRM_DRIVERS = intel nouveau
+WAYLAND_INTERFACES = shm
+
+ifeq ($(ENABLE_DRM),1)
+ WAYLAND_INTERFACES += drm
+endif
+
diff --git a/src/wld/context.c b/src/wld/context.c
new file mode 100644
index 0000000..a735d40
--- /dev/null
+++ b/src/wld/context.c
@@ -0,0 +1,70 @@
+/* wld: context.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wld-private.h"
+
+void context_initialize(struct wld_context * context,
+ const struct wld_context_impl * impl)
+{
+ *((const struct wld_context_impl **) &context->impl) = impl;
+}
+
+EXPORT
+struct wld_renderer * wld_create_renderer(struct wld_context * context)
+{
+ return context->impl->create_renderer(context);
+}
+
+EXPORT
+struct wld_buffer * wld_create_buffer(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ return &context->impl->create_buffer(context, width, height,
+ format, flags)->base;
+}
+
+EXPORT
+struct wld_buffer * wld_import_buffer(struct wld_context * context,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ return &context->impl->import_buffer(context, type, object,
+ width, height, format, pitch)->base;
+}
+
+EXPORT
+struct wld_surface * wld_create_surface(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ return context->impl->create_surface(context, width, height, format, flags);
+}
+
+EXPORT
+void wld_destroy_context(struct wld_context * context)
+{
+ context->impl->destroy(context);
+}
+
diff --git a/src/wld/drm-private.h b/src/wld/drm-private.h
new file mode 100644
index 0000000..6c36088
--- /dev/null
+++ b/src/wld/drm-private.h
@@ -0,0 +1,46 @@
+/* wld: drm-private.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_DRM_PRIVATE_H
+#define WLD_DRM_PRIVATE_H
+
+#include "wld-private.h"
+
+struct drm_driver
+{
+ const char * name;
+ bool (* device_supported)(uint32_t vendor_id, uint32_t device_id);
+ struct wld_context * (* create_context)(int drm_fd);
+};
+
+#if WITH_DRM_INTEL
+extern const struct drm_driver intel_drm_driver;
+#endif
+#if WITH_DRM_NOUVEAU
+extern const struct drm_driver nouveau_drm_driver;
+#endif
+extern const struct drm_driver dumb_drm_driver;
+extern const struct wld_context_impl * dumb_context_impl;
+
+#endif
+
diff --git a/src/wld/drm.c b/src/wld/drm.c
new file mode 100644
index 0000000..2768640
--- /dev/null
+++ b/src/wld/drm.c
@@ -0,0 +1,98 @@
+/* wld: drm.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "drm.h"
+#include "drm-private.h"
+
+#include <sys/sysmacros.h>
+
+const static struct drm_driver * drivers[] = {
+#if WITH_DRM_INTEL
+ &intel_drm_driver,
+#endif
+#if WITH_DRM_NOUVEAU
+ &nouveau_drm_driver,
+#endif
+ &dumb_drm_driver
+};
+
+static const struct drm_driver * find_driver(int fd)
+{
+ char path[64], id[32];
+ uint32_t vendor_id, device_id;
+ char * path_part;
+ struct stat st;
+ FILE * file;
+ uint32_t index;
+
+ if (fstat(fd, &st) == -1)
+ return NULL;
+
+ path_part = path + snprintf(path, sizeof path,
+ "/sys/dev/char/%u:%u/device/",
+ major(st.st_rdev), minor(st.st_rdev));
+
+ strcpy(path_part, "vendor");
+ file = fopen(path, "r");
+ fgets(id, sizeof id, file);
+ fclose(file);
+ vendor_id = strtoul(id, NULL, 0);
+
+ strcpy(path_part, "device");
+ file = fopen(path, "r");
+ fgets(id, sizeof id, file);
+ fclose(file);
+ device_id = strtoul(id, NULL, 0);
+
+ if (getenv("WLD_DRM_DUMB"))
+ return &dumb_drm_driver;
+
+ for (index = 0; index < ARRAY_LENGTH(drivers); ++index)
+ {
+ DEBUG("Trying DRM driver `%s'\n", drivers[index]->name);
+ if (drivers[index]->device_supported(vendor_id, device_id))
+ return drivers[index];
+ }
+
+ DEBUG("No DRM driver supports device 0x%x:0x%x\n", vendor_id, device_id);
+
+ return NULL;
+}
+
+EXPORT
+struct wld_context * wld_drm_create_context(int fd)
+{
+ const struct drm_driver * driver;
+
+ if (!(driver = find_driver(fd)))
+ return NULL;
+
+ return driver->create_context(fd);
+}
+
+EXPORT
+bool wld_drm_is_dumb(struct wld_context * context)
+{
+ return context->impl == dumb_context_impl;
+}
+
diff --git a/src/wld/drm.h b/src/wld/drm.h
new file mode 100644
index 0000000..20ee3e8
--- /dev/null
+++ b/src/wld/drm.h
@@ -0,0 +1,52 @@
+/* wld: drm.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_DRM_H
+#define WLD_DRM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define WLD_DRM_ID (0x02 << 24)
+
+enum wld_drm_object_type
+{
+ WLD_DRM_OBJECT_HANDLE = WLD_DRM_ID,
+ WLD_DRM_OBJECT_PRIME_FD,
+};
+
+enum wld_drm_flags
+{
+ WLD_DRM_FLAG_SCANOUT = 0x1,
+ WLD_DRM_FLAG_TILED = 0x2
+};
+
+/**
+ * Create a new WLD context from an opened DRM device file descriptor.
+ */
+struct wld_context * wld_drm_create_context(int fd);
+
+bool wld_drm_is_dumb(struct wld_context * context);
+
+#endif
+
diff --git a/src/wld/dumb.c b/src/wld/dumb.c
new file mode 100644
index 0000000..b08d098
--- /dev/null
+++ b/src/wld/dumb.c
@@ -0,0 +1,235 @@
+/* wld: dumb.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "drm-private.h"
+#include "drm.h"
+#include "pixman.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <xf86drm.h>
+
+#include <errno.h>
+
+struct dumb_context
+{
+ struct wld_context base;
+ int fd;
+};
+
+struct dumb_buffer
+{
+ struct buffer base;
+ struct wld_exporter exporter;
+ struct dumb_context * context;
+ uint32_t handle;
+};
+
+#include "interface/context.h"
+#include "interface/buffer.h"
+#define DRM_DRIVER_NAME dumb
+#include "interface/drm.h"
+IMPL(dumb_context, wld_context)
+IMPL(dumb_buffer, wld_buffer)
+
+const struct wld_context_impl * dumb_context_impl = &wld_context_impl;
+
+bool driver_device_supported(uint32_t vendor_id, uint32_t device_id)
+{
+ return true;
+}
+
+struct wld_context * driver_create_context(int drm_fd)
+{
+ struct dumb_context * context;
+
+ if (!(context = malloc(sizeof *context)))
+ return NULL;
+
+ context_initialize(&context->base, &wld_context_impl);
+ context->fd = drm_fd;
+
+ return &context->base;
+}
+
+struct wld_renderer * context_create_renderer(struct wld_context * context)
+{
+ return wld_create_renderer(wld_pixman_context);
+}
+
+static bool export(struct wld_exporter * exporter, struct wld_buffer * base,
+ uint32_t type, union wld_object * object)
+{
+ struct dumb_buffer * buffer = dumb_buffer(base);
+
+ switch (type)
+ {
+ case WLD_DRM_OBJECT_HANDLE:
+ object->u32 = buffer->handle;
+ return true;
+ case WLD_DRM_OBJECT_PRIME_FD:
+ if (drmPrimeHandleToFD(buffer->context->fd, buffer->handle,
+ DRM_CLOEXEC, &object->i) != 0)
+ {
+ return false;
+ }
+
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct buffer * new_buffer(struct dumb_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t handle,
+ unsigned long pitch)
+{
+ struct dumb_buffer * buffer;
+
+ if (!(buffer = malloc(sizeof *buffer)))
+ return NULL;
+
+ buffer_initialize(&buffer->base, &wld_buffer_impl,
+ width, height, format, pitch);
+ buffer->context = context;
+ buffer->handle = handle;
+ buffer->exporter.export = &export;
+ wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
+
+ return &buffer->base;
+}
+
+struct buffer * context_create_buffer(struct wld_context * base,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ struct dumb_context * context = dumb_context(base);
+ struct buffer * buffer;
+ struct drm_mode_create_dumb create_dumb = {
+ .height = height, .width = width,
+ .bpp = format_bytes_per_pixel(format) * 8,
+ };
+
+ if (drmIoctl(context->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) != 0)
+ goto error0;
+
+ buffer = new_buffer(context, width, height, format,
+ create_dumb.handle, create_dumb.pitch);
+
+ if (!buffer)
+ goto error1;
+
+ return buffer;
+
+ error1:
+ {
+ struct drm_mode_destroy_dumb destroy_dumb = {
+ .handle = create_dumb.handle
+ };
+
+ drmIoctl(context->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
+ }
+ error0:
+ return NULL;
+}
+
+struct buffer * context_import_buffer(struct wld_context * base,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ struct dumb_context * context = dumb_context(base);
+ uint32_t handle;
+
+ switch (type)
+ {
+ case WLD_DRM_OBJECT_PRIME_FD:
+ if (drmPrimeFDToHandle(context->fd, object.i, &handle) != 0)
+ return NULL;
+ break;
+ default: return NULL;
+ }
+
+ return new_buffer(context, width, height, format, handle, pitch);
+}
+
+void context_destroy(struct wld_context * base)
+{
+ struct dumb_context * context = dumb_context(base);
+
+ close(context->fd);
+ free(context);
+}
+
+/**** Buffer ****/
+
+bool buffer_map(struct buffer * base)
+{
+ struct dumb_buffer * buffer = dumb_buffer(&base->base);
+ struct drm_mode_map_dumb map_dumb = { .handle = buffer->handle };
+ void * data;
+
+ if (drmIoctl(buffer->context->fd, DRM_IOCTL_MODE_MAP_DUMB,
+ &map_dumb) != 0)
+ {
+ return false;
+ }
+
+ data = mmap(NULL, buffer->base.base.pitch * buffer->base.base.height,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ buffer->context->fd, map_dumb.offset);
+
+ if (data == MAP_FAILED)
+ return false;
+
+ buffer->base.base.map = data;
+
+ return true;
+}
+
+bool buffer_unmap(struct buffer * buffer)
+{
+ if (munmap(buffer->base.map,
+ buffer->base.pitch * buffer->base.height) == -1)
+ {
+ return false;
+ }
+
+ buffer->base.map = NULL;
+
+ return true;
+}
+
+void buffer_destroy(struct buffer * base)
+{
+ struct dumb_buffer * buffer = dumb_buffer(&base->base);
+ struct drm_mode_destroy_dumb destroy_dumb = {
+ .handle = buffer->handle
+ };
+
+ drmIoctl(buffer->context->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
+ free(buffer);
+}
+
diff --git a/src/wld/font.c b/src/wld/font.c
new file mode 100644
index 0000000..36b8a07
--- /dev/null
+++ b/src/wld/font.c
@@ -0,0 +1,235 @@
+/* wld: font.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wld-private.h"
+
+#include <fontconfig/fcfreetype.h>
+
+EXPORT
+struct wld_font_context * wld_font_create_context()
+{
+ struct wld_font_context * context;
+
+ context = malloc(sizeof *context);
+
+ if (!context)
+ goto error0;
+
+ if (FT_Init_FreeType(&context->library) != 0)
+ {
+ DEBUG("Failed to initialize FreeType library\n");
+
+ goto error1;
+ }
+
+ return context;
+
+ error1:
+ free(context);
+ error0:
+ return NULL;
+}
+
+EXPORT
+void wld_font_destroy_context(struct wld_font_context * context)
+{
+ FT_Done_FreeType(context->library);
+ free(context);
+}
+
+EXPORT
+struct wld_font * wld_font_open_name(struct wld_font_context * context,
+ const char * name)
+{
+ FcPattern * pattern, * match;
+ FcResult result;
+
+ DEBUG("Opening font with name: %s\n", name);
+
+ pattern = FcNameParse((const FcChar8 *) name);
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ match = FcFontMatch(NULL, pattern, &result);
+
+ if (!match)
+ return NULL;
+
+ return wld_font_open_pattern(context, match);
+}
+
+EXPORT
+struct wld_font * wld_font_open_pattern(struct wld_font_context * context,
+ FcPattern * match)
+{
+ char * filename;
+ struct font * font;
+ FcResult result;
+ double pixel_size, aspect;
+
+ font = malloc(sizeof *font);
+
+ if (!font)
+ goto error0;
+
+ font->context = context;
+
+ result = FcPatternGetString(match, FC_FILE, 0, (FcChar8 **) &filename);
+
+ if (result == FcResultMatch)
+ {
+ FT_Error error;
+
+ DEBUG("Loading font file: %s\n", filename);
+
+ error = FT_New_Face(context->library, filename, 0, &font->face);
+
+ if (error == 0)
+ goto load_face;
+ }
+
+ result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &font->face);
+
+ if (result != FcResultMatch)
+ {
+ DEBUG("Couldn't determine font filename or FreeType face\n");
+ goto error1;
+ }
+
+ load_face:
+ result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixel_size);
+
+ result = FcPatternGetDouble(match, FC_ASPECT, 0, &aspect);
+
+ if (result == FcResultNoMatch)
+ aspect = 1.0;
+
+ if (font->face->face_flags & FT_FACE_FLAG_SCALABLE)
+ {
+ FT_F26Dot6 width, height;
+
+ width = ((unsigned int) pixel_size) << 6;
+ height = ((unsigned int) (pixel_size * aspect)) << 6;
+
+ FT_Set_Char_Size(font->face, width, height, 0, 0);
+ }
+ else
+ {
+ FT_Set_Pixel_Sizes(font->face, (unsigned int) pixel_size,
+ (unsigned int) (pixel_size * aspect));
+ }
+
+ font->base.ascent = font->face->size->metrics.ascender >> 6;
+ font->base.descent = -font->face->size->metrics.descender >> 6;
+ font->base.height = font->base.ascent + font->base.descent;
+ font->base.max_advance = font->face->size->metrics.max_advance >> 6;
+
+ font->glyphs = calloc(font->face->num_glyphs, sizeof(struct glyph *));
+
+ return &font->base;
+
+ error1:
+ free(font);
+ error0:
+ return NULL;
+}
+
+EXPORT
+void wld_font_close(struct wld_font * font_base)
+{
+ struct font * font = (void *) font_base;
+
+ FT_Done_Face(font->face);
+ free(font);
+}
+
+bool font_ensure_glyph(struct font * font, FT_UInt glyph_index)
+{
+ if (glyph_index)
+ {
+ if (!font->glyphs[glyph_index])
+ {
+ struct glyph * glyph;
+
+ glyph = malloc(sizeof *glyph);
+
+ if (!glyph)
+ return false;
+
+ FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER
+ | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO);
+
+ FT_Bitmap_New(&glyph->bitmap);
+
+ FT_Bitmap_Copy(font->context->library,
+ &font->face->glyph->bitmap, &glyph->bitmap);
+
+ glyph->advance = font->face->glyph->metrics.horiAdvance >> 6;
+ glyph->x = font->face->glyph->bitmap_left;
+ glyph->y = -font->face->glyph->bitmap_top;
+
+ font->glyphs[glyph_index] = glyph;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+EXPORT
+bool wld_font_ensure_char(struct wld_font * font_base, uint32_t character)
+{
+ struct font * font = (void *) font_base;
+ FT_UInt glyph_index;
+
+ glyph_index = FT_Get_Char_Index(font->face, character);
+
+ return font_ensure_glyph(font, glyph_index);
+}
+
+EXPORT
+void wld_font_text_extents_n(struct wld_font * font_base,
+ const char * text, int32_t length,
+ struct wld_extents * extents)
+{
+ struct font * font = (void *) font_base;
+ int ret;
+ uint32_t c;
+ FT_UInt glyph_index;
+
+ extents->advance = 0;
+
+ while ((ret = FcUtf8ToUcs4((FcChar8 *) text, &c, length) > 0) && c != '\0')
+ {
+ length -= ret;
+ text += ret;
+ glyph_index = FT_Get_Char_Index(font->face, c);
+
+ if (!font_ensure_glyph(font, glyph_index))
+ continue;
+
+ extents->advance += font->glyphs[glyph_index]->advance;
+ }
+}
+
diff --git a/src/wld/intel.c b/src/wld/intel.c
new file mode 100644
index 0000000..78c3c0f
--- /dev/null
+++ b/src/wld/intel.c
@@ -0,0 +1,390 @@
+/* wld: intel.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "drm-private.h"
+#include "drm.h"
+#include "intel/batch.h"
+#include "intel/blt.h"
+#include "wld-private.h"
+
+#include <unistd.h>
+#include <intel_bufmgr.h>
+#include <i915_drm.h>
+
+struct intel_context
+{
+ struct wld_context base;
+ drm_intel_bufmgr * bufmgr;
+};
+
+struct intel_renderer
+{
+ struct wld_renderer base;
+ struct intel_batch batch;
+ struct intel_buffer * target;
+};
+
+struct intel_buffer
+{
+ struct buffer base;
+ struct wld_exporter exporter;
+ drm_intel_bo * bo;
+};
+
+#include "interface/context.h"
+#include "interface/renderer.h"
+#include "interface/buffer.h"
+#define DRM_DRIVER_NAME intel
+#include "interface/drm.h"
+IMPL(intel_context, wld_context)
+IMPL(intel_renderer, wld_renderer)
+IMPL(intel_buffer, wld_buffer)
+
+/**** DRM driver ****/
+bool driver_device_supported(uint32_t vendor_id, uint32_t device_id)
+{
+ return vendor_id == 0x8086;
+}
+
+struct wld_context * driver_create_context(int drm_fd)
+{
+ struct intel_context * context;
+
+ context = malloc(sizeof *context);
+
+ if (!context)
+ goto error0;
+
+ context_initialize(&context->base, &wld_context_impl);
+ context->bufmgr = drm_intel_bufmgr_gem_init(drm_fd, INTEL_BATCH_SIZE);
+
+ if (!context->bufmgr)
+ goto error1;
+
+ return &context->base;
+
+ error1:
+ free(context);
+ error0:
+ return NULL;
+}
+
+/**** Context ****/
+struct wld_renderer * context_create_renderer(struct wld_context * base)
+{
+ struct intel_context * context = intel_context(base);
+ struct intel_renderer * renderer;
+
+ if (!(renderer = malloc(sizeof *renderer)))
+ goto error0;
+
+ if (!(intel_batch_initialize(&renderer->batch, context->bufmgr)))
+ goto error1;
+
+ renderer_initialize(&renderer->base, &wld_renderer_impl);
+
+ return &renderer->base;
+
+ error1:
+ free(renderer);
+ error0:
+ return NULL;
+}
+
+static bool export(struct wld_exporter * exporter, struct wld_buffer * base,
+ uint32_t type, union wld_object * object)
+{
+ struct intel_buffer * buffer = intel_buffer(base);
+
+ switch (type)
+ {
+ case WLD_DRM_OBJECT_HANDLE:
+ object->u32 = buffer->bo->handle;
+ return true;
+ case WLD_DRM_OBJECT_PRIME_FD:
+ if (drm_intel_bo_gem_export_to_prime(buffer->bo, &object->i) != 0)
+ return false;
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct buffer * new_buffer(uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch,
+ drm_intel_bo * bo)
+{
+ struct intel_buffer * buffer;
+
+ if (!(buffer = malloc(sizeof *buffer)))
+ return NULL;
+
+ buffer_initialize(&buffer->base, &wld_buffer_impl,
+ width, height, format, pitch);
+ buffer->bo = bo;
+ buffer->exporter.export = &export;
+ wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
+
+ return &buffer->base;
+}
+
+struct buffer * context_create_buffer(struct wld_context * base,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ struct intel_context * context = intel_context(base);
+ struct buffer * buffer;
+ drm_intel_bo * bo;
+ uint32_t tiling_mode = width >= 128 ? I915_TILING_X : I915_TILING_NONE;
+ unsigned long pitch;
+
+ bo = drm_intel_bo_alloc_tiled(context->bufmgr, "buffer", width, height, 4,
+ &tiling_mode, &pitch, 0);
+
+ if (!bo)
+ goto error0;
+
+ if (!(buffer = new_buffer(width, height, format, pitch, bo)))
+ goto error1;
+
+ return buffer;
+
+ error1:
+ drm_intel_bo_unreference(bo);
+ error0:
+ return NULL;
+}
+
+struct buffer * context_import_buffer(struct wld_context * base,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ struct intel_context * context = intel_context(base);
+ struct buffer * buffer;
+ drm_intel_bo * bo;
+
+ switch (type)
+ {
+ case WLD_DRM_OBJECT_PRIME_FD:
+ {
+ uint32_t size = width * height * format_bytes_per_pixel(format);
+ bo = drm_intel_bo_gem_create_from_prime(context->bufmgr,
+ object.i, size);
+ break;
+ }
+ default: bo = NULL;
+ };
+
+ if (!bo)
+ goto error0;
+
+ if (!(buffer = new_buffer(width, height, format, pitch, bo)))
+ goto error1;
+
+ return buffer;
+
+ error1:
+ drm_intel_bo_unreference(bo);
+ error0:
+ return NULL;
+}
+
+void context_destroy(struct wld_context * base)
+{
+ struct intel_context * context = intel_context(base);
+
+ drm_intel_bufmgr_destroy(context->bufmgr);
+ free(context);
+}
+
+/**** Renderer ****/
+uint32_t renderer_capabilities(struct wld_renderer * renderer,
+ struct buffer * buffer)
+{
+ if (buffer->base.impl == &wld_buffer_impl)
+ return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE;
+
+ return 0;
+}
+
+bool renderer_set_target(struct wld_renderer * base, struct buffer * buffer)
+{
+ struct intel_renderer * renderer = intel_renderer(base);
+
+ if (buffer && buffer->base.impl != &wld_buffer_impl)
+ return false;
+
+ renderer->target = buffer ? intel_buffer(&buffer->base) : NULL;
+
+ return true;
+}
+
+void renderer_fill_rectangle(struct wld_renderer * base, uint32_t color,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct intel_renderer * renderer = intel_renderer(base);
+ struct intel_buffer * dst = renderer->target;
+
+ xy_color_blt(&renderer->batch, dst->bo, dst->base.base.pitch,
+ x, y, x + width, y + height, color);
+}
+
+void renderer_copy_rectangle(struct wld_renderer * base,
+ struct buffer * buffer_base,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height)
+{
+ struct intel_renderer * renderer = intel_renderer(base);
+
+ if (buffer_base->base.impl != &wld_buffer_impl)
+ return;
+
+ struct intel_buffer * src = intel_buffer(&buffer_base->base),
+ * dst = renderer->target;
+
+ xy_src_copy_blt(&renderer->batch,
+ src->bo, src->base.base.pitch, src_x, src_y,
+ dst->bo, dst->base.base.pitch, dst_x, dst_y, width, height);
+}
+
+void renderer_draw_text(struct wld_renderer * base,
+ struct font * font, uint32_t color,
+ int32_t x, int32_t y, const char * text,
+ uint32_t length, struct wld_extents * extents)
+{
+ struct intel_renderer * renderer = intel_renderer(base);
+ struct intel_buffer * dst = renderer->target;
+ int ret;
+ struct glyph * glyph;
+ uint32_t row;
+ FT_UInt glyph_index;
+ uint32_t c;
+ uint8_t immediate[512];
+ uint8_t * byte;
+ int32_t origin_x = x;
+
+ xy_setup_blt(&renderer->batch, true, BLT_RASTER_OPERATION_SRC,
+ 0, color, dst->bo, dst->base.base.pitch);
+
+ if (length == -1)
+ length = strlen(text);
+
+ while ((ret = FcUtf8ToUcs4((FcChar8 *) text, &c, length)) > 0 && c != '\0')
+ {
+ text += ret;
+ length -= ret;
+ glyph_index = FT_Get_Char_Index(font->face, c);
+
+ if (!font_ensure_glyph(font, glyph_index))
+ continue;
+
+ glyph = font->glyphs[glyph_index];
+
+ if (glyph->bitmap.width == 0 || glyph->bitmap.rows == 0)
+ goto advance;
+
+ byte = immediate;
+
+ /* XY_TEXT_IMMEDIATE requires a pitch with no extra bytes */
+ for (row = 0; row < glyph->bitmap.rows; ++row)
+ {
+ memcpy(byte, glyph->bitmap.buffer + (row * glyph->bitmap.pitch),
+ (glyph->bitmap.width + 7) / 8);
+ byte += (glyph->bitmap.width + 7) / 8;
+ }
+
+ retry:
+ ret = xy_text_immediate_blt(&renderer->batch, dst->bo,
+ origin_x + glyph->x, y + glyph->y,
+ origin_x + glyph->x + glyph->bitmap.width,
+ y + glyph->y + glyph->bitmap.rows,
+ (byte - immediate + 3) / 4,
+ (uint32_t *) immediate);
+
+ if (ret == INTEL_BATCH_NO_SPACE)
+ {
+ intel_batch_flush(&renderer->batch);
+ xy_setup_blt(&renderer->batch, true, BLT_RASTER_OPERATION_SRC,
+ 0, color, dst->bo, dst->base.base.pitch);
+ goto retry;
+ }
+
+ advance:
+ origin_x += glyph->advance;
+ }
+
+ if (extents)
+ extents->advance = origin_x - x;
+}
+
+void renderer_flush(struct wld_renderer * base)
+{
+ struct intel_renderer * renderer = intel_renderer(base);
+
+ intel_batch_flush(&renderer->batch);
+}
+
+void renderer_destroy(struct wld_renderer * base)
+{
+ struct intel_renderer * renderer = intel_renderer(base);
+
+ intel_batch_finalize(&renderer->batch);
+ free(renderer);
+}
+
+/**** Buffer ****/
+bool buffer_map(struct buffer * base)
+{
+ struct intel_buffer * buffer = intel_buffer(&base->base);
+
+ if (drm_intel_gem_bo_map_gtt(buffer->bo) != 0)
+ return false;
+
+ buffer->base.base.map = buffer->bo->virtual;
+
+ return true;
+}
+
+bool buffer_unmap(struct buffer * base)
+{
+ struct intel_buffer * buffer = intel_buffer(&base->base);
+
+ if (drm_intel_gem_bo_unmap_gtt(buffer->bo) != 0)
+ return false;
+
+ buffer->base.base.map = NULL;
+
+ return true;
+}
+
+void buffer_destroy(struct buffer * base)
+{
+ struct intel_buffer * buffer = intel_buffer(&base->base);
+
+ drm_intel_bo_unreference(buffer->bo);
+ free(buffer);
+}
+
diff --git a/src/wld/intel/batch.c b/src/wld/intel/batch.c
new file mode 100644
index 0000000..61d9ecf
--- /dev/null
+++ b/src/wld/intel/batch.c
@@ -0,0 +1,99 @@
+/* wld: intel/batch.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "batch.h"
+#include "mi.h"
+
+#include <i915_drm.h>
+#include <stdlib.h>
+
+static const struct intel_device_info device_info_i965 = { .gen = 4 };
+static const struct intel_device_info device_info_g4x = { .gen = 4 };
+static const struct intel_device_info device_info_ilk = { .gen = 5 };
+static const struct intel_device_info device_info_snb_gt1 = { .gen = 6 };
+static const struct intel_device_info device_info_snb_gt2 = { .gen = 6 };
+static const struct intel_device_info device_info_ivb_gt1 = { .gen = 7 };
+static const struct intel_device_info device_info_ivb_gt2 = { .gen = 7 };
+static const struct intel_device_info device_info_byt = { .gen = 7 };
+static const struct intel_device_info device_info_hsw_gt1 = { .gen = 7 };
+static const struct intel_device_info device_info_hsw_gt2 = { .gen = 7 };
+static const struct intel_device_info device_info_hsw_gt3 = { .gen = 7 };
+
+static const struct intel_device_info * device_info(int device_id)
+{
+ switch (device_id)
+ {
+#define CHIPSET(device_id, type, name) \
+ case device_id: return &device_info_ ## type;
+#include "i965_pci_ids.h"
+#undef CHIPSET
+ default: return NULL;
+ }
+}
+
+bool intel_batch_initialize(struct intel_batch * batch,
+ drm_intel_bufmgr * bufmgr)
+{
+ int device_id = drm_intel_bufmgr_gem_get_devid(bufmgr);
+
+ batch->command_count = 0;
+ batch->device_info = device_info(device_id);
+
+ if (!batch->device_info)
+ return false;
+
+ /* Alignment argument (4096) is not used */
+ batch->bo = drm_intel_bo_alloc(bufmgr, "batchbuffer",
+ sizeof batch->commands, 4096);
+
+ if (!batch->bo)
+ return false;
+
+ return true;
+}
+
+void intel_batch_finalize(struct intel_batch * batch)
+{
+ drm_intel_bo_unreference(batch->bo);
+}
+
+void intel_batch_flush(struct intel_batch * batch)
+{
+ if (batch->command_count == 0)
+ return;
+
+ intel_batch_add_dword(batch, MI_BATCH_BUFFER_END);
+
+ /* Pad the batch buffer to the next quad-word. */
+ if (batch->command_count & 1)
+ intel_batch_add_dword(batch, MI_NOOP);
+
+ drm_intel_bo_subdata(batch->bo, 0, batch->command_count << 2,
+ batch->commands);
+ drm_intel_bo_mrb_exec(batch->bo, batch->command_count << 2, NULL, 0, 0,
+ batch->device_info->gen >= 6 ? I915_EXEC_BLT
+ : I915_EXEC_DEFAULT);
+ drm_intel_gem_bo_clear_relocs(batch->bo, 0);
+ batch->command_count = 0;
+}
+
diff --git a/src/wld/intel/batch.h b/src/wld/intel/batch.h
new file mode 100644
index 0000000..d09eb27
--- /dev/null
+++ b/src/wld/intel/batch.h
@@ -0,0 +1,104 @@
+/* wld: intel/batch.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_INTEL_BATCH_H
+#define WLD_INTEL_BATCH_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <intel_bufmgr.h>
+
+#define INTEL_BATCH_MAX_COMMANDS (1 << 13)
+#define INTEL_BATCH_RESERVED_COMMANDS 2
+#define INTEL_BATCH_SIZE (INTEL_BATCH_MAX_COMMANDS << 2)
+
+enum intel_batch_result
+{
+ INTEL_BATCH_SUCCESS,
+ INTEL_BATCH_NO_SPACE
+};
+
+struct intel_device_info
+{
+ int gen;
+};
+
+struct intel_batch
+{
+ const struct intel_device_info * device_info;
+ drm_intel_bo * bo;
+ uint32_t commands[INTEL_BATCH_MAX_COMMANDS];
+ uint32_t command_count;
+};
+
+bool intel_batch_initialize(struct intel_batch * batch,
+ drm_intel_bufmgr * bufmgr);
+
+void intel_batch_finalize(struct intel_batch * batch);
+
+void intel_batch_flush(struct intel_batch * batch);
+
+static inline uint32_t intel_batch_check_space(struct intel_batch * batch,
+ uint32_t size)
+{
+ return (INTEL_BATCH_MAX_COMMANDS - INTEL_BATCH_RESERVED_COMMANDS
+ - batch->command_count) >= size;
+}
+
+static inline void intel_batch_ensure_space(struct intel_batch * batch, uint32_t size)
+{
+ if (!intel_batch_check_space(batch, size))
+ intel_batch_flush(batch);
+}
+
+static inline void intel_batch_add_dword(struct intel_batch * batch,
+ uint32_t dword)
+{
+ batch->commands[batch->command_count++] = dword;
+}
+
+static inline void intel_batch_add_dwords_va(struct intel_batch * batch,
+ uint32_t count, va_list dwords)
+{
+ while (count--)
+ intel_batch_add_dword(batch, va_arg(dwords, uint32_t));
+}
+
+static inline void intel_batch_add_dwords(struct intel_batch * batch,
+ uint32_t count, ...)
+{
+ va_list dwords;
+ va_start(dwords, count);
+ intel_batch_add_dwords_va(batch, count, dwords);
+ va_end(dwords);
+}
+
+static inline uint32_t intel_batch_offset(struct intel_batch * batch,
+ uint32_t command_index)
+{
+ return (batch->command_count + command_index) << 2;
+}
+
+#endif
+
diff --git a/src/wld/intel/blt.h b/src/wld/intel/blt.h
new file mode 100644
index 0000000..a90c921
--- /dev/null
+++ b/src/wld/intel/blt.h
@@ -0,0 +1,347 @@
+/* wld: intel/blt.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_INTEL_BLT_H
+#define WLD_INTEL_BLT_H
+
+#include <i915_drm.h>
+#include <intel_bufmgr.h>
+
+#define INTEL_CLIENT_BLT 0x2
+
+enum blt_op
+{
+ BLT_OP_XY_SETUP_BLT = 0x01,
+ BLT_OP_XY_TEXT_BLT = 0x26,
+ BLT_OP_XY_TEXT_IMMEDIATE_BLT = 0x31,
+ BLT_OP_XY_COLOR_BLT = 0x50,
+ BLT_OP_XY_SRC_COPY_BLT = 0x53
+};
+
+enum blt_32bpp_mask
+{
+ BLT_32BPP_MASK_ALPHA = (1 << 0),
+ BLT_32BPP_MASK_RGB = (1 << 1)
+};
+
+enum blt_packing
+{
+ BLT_PACKING_BIT = 0,
+ BLT_PACKING_BYTE = 1
+};
+
+enum blt_color_depth
+{
+ BLT_COLOR_DEPTH_8BIT = 0x0,
+ BLT_COLOR_DEPTH_16BIT_565 = 0x1,
+ BLT_COLOR_DEPTH_16BIT_1555 = 0x2,
+ BLT_COLOR_DEPTH_32BIT = 0x3
+};
+
+enum blt_raster_operation
+{
+ BLT_RASTER_OPERATION_SRC = 0xcc,
+ BLT_RASTER_OPERATION_PAT = 0xf0
+};
+
+/* BR00 : BLT Opcode & Control */
+#define BLT_BR00_CLIENT(x) ((x) << 29) /* 31:29 */
+#define BLT_BR00_OP(x) ((x) << 22) /* 28:22 */
+#define BLT_BR00_32BPP_MASK(x) ((x) << 20) /* 21:20 */
+ /* 19:17 */
+#define BLT_BR00_PACKING(x) ((x) << 16) /* 16 */
+#define BLT_BR00_SRC_TILING_ENABLE(x) ((x) << 15) /* 15 */
+ /* 14:12 */
+#define BLT_BR00_DST_TILING_ENABLE(x) ((x) << 11) /* 11 */
+#define BLT_BR00_DWORD_LENGTH(x) ((x) << 0) /* 7:0 */
+
+/* BR01 : Setup BLT Raster OP, Control, and Destination Offset */
+#define BLT_BR01_SOLID_PATTERN(x) ((x) << 31) /* 31 */
+#define BLT_BR01_CLIPPING_ENABLE(x) ((x) << 30) /* 30 */
+#define BLT_BR01_MONO_SRC_TRANSPARENCY(x) ((x) << 29) /* 29 */
+#define BLT_BR01_MONO_PAT_TRANSPARENCY(x) ((x) << 28) /* 28 */
+#define BLT_BR01_COLOR_DEPTH(x) ((x) << 24) /* 25:24 */
+#define BLT_BR01_RASTER_OPERATION(x) ((x) << 16) /* 23:16 */
+#define BLT_BR01_DST_PITCH(x) ((x) << 0) /* 15:0 */
+
+/* BR05 : Setup Expansion Background Color */
+#define BLT_BR05_BACKGROUND_COLOR(x) ((x) << 0) /* 31:0 */
+
+/* BR06 : Setup Expansion Foreground Color */
+#define BLT_BR06_FOREGROUND_COLOR(x) ((x) << 0) /* 31:0 */
+
+/* BR07 : Setup Blit Color Pattern Address */
+ /* 31:29 */
+#define BLT_BR07_PAT_ADDRESS(x) ((x) << 6) /* 28:6 */
+ /* 5:0 */
+
+/* BR09 : Destination Address */
+ /* 31:29 */
+#define BLT_BR09_DST_ADDRESS(x) ((x) << 0) /* 28:0 */
+
+/* BR11 : Source Pitch */
+ /* 31:16 */
+#define BLT_BR11_SRC_PITCH(x) ((x) << 0) /* 15:0 */
+
+/* BR12 : Source Address */
+ /* 31:29 */
+#define BLT_BR12_SRC_ADDRESS(x) ((x) << 0) /* 28:0 */
+
+/* BR13 : BLT Raster OP, Control, and Destination Pitch */
+#define BLT_BR13_SOLID_PATTERN(x) ((x) << 31) /* 31 */
+#define BLT_BR13_CLIPPING_ENABLE(x) ((x) << 30) /* 30 */
+#define BLT_BR13_MONO_SRC_TRANSPARENT(x) ((x) << 29) /* 29 */
+#define BLT_BR13_MONO_PAT_TRANSPARENT(x) ((x) << 28) /* 28 */
+#define BLT_BR13_COLOR_DEPTH(x) ((x) << 24) /* 25:24 */
+#define BLT_BR13_RASTER_OPERATION(x) ((x) << 16) /* 23:16 */
+#define BLT_BR13_DST_PITCH(x) ((x) << 0) /* 15:0 */
+
+/* BR16 : Pattern Expansion Background & Solid Pattern Color */
+#define BLT_BR16_COLOR(x) ((x) << 0) /* 31 : 0 */
+
+/* BR22 : Destination Top Left */
+#define BLT_BR22_DST_Y1(x) ((x) << 16) /* 31:16 */
+#define BLT_BR22_DST_X1(x) ((x) << 0) /* 16:0 */
+
+/* BR23 : Destination Bottom Right */
+#define BLT_BR23_DST_Y2(x) ((x) << 16) /* 31:16 */
+#define BLT_BR23_DST_X2(x) ((x) << 0) /* 16:0 */
+
+/* BR24 : Clip Rectangle Top Left */
+ /* 31 */
+#define BLT_BR24_CLP_Y1(x) ((x) << 16) /* 30:16 */
+ /* 15 */
+#define BLT_BR24_CLP_X1(x) ((x) << 0) /* 14:0 */
+
+/* BR25 : Clip Rectangle Bottom Right */
+ /* 31 */
+#define BLT_BR25_CLP_Y2(x) ((x) << 16) /* 30:16 */
+ /* 15 */
+#define BLT_BR25_CLP_X2(x) ((x) << 0) /* 14:0 */
+
+/* BR26 : Source Top Left */
+#define BLT_BR26_SRC_Y1(x) ((x) << 16) /* 31:16 */
+#define BLT_BR26_SRC_X1(x) ((x) << 0) /* 15:0 */
+
+static inline void xy_setup_blt(struct intel_batch * batch,
+ bool monochrome_source_transparency,
+ uint8_t raster_operation,
+ uint32_t background_color,
+ uint32_t foreground_color,
+ drm_intel_bo * dst, uint16_t dst_pitch)
+{
+ uint32_t tiling_mode, swizzle_mode;
+
+ intel_batch_ensure_space(batch, 8);
+
+ drm_intel_bo_get_tiling(dst, &tiling_mode, &swizzle_mode);
+ drm_intel_bo_emit_reloc_fence
+ (batch->bo, intel_batch_offset(batch, 4), dst, 0,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+
+ intel_batch_add_dwords(batch, 8,
+ BLT_BR00_CLIENT(INTEL_CLIENT_BLT)
+ | BLT_BR00_OP(BLT_OP_XY_SETUP_BLT)
+ | BLT_BR00_32BPP_MASK(BLT_32BPP_MASK_ALPHA | BLT_32BPP_MASK_RGB)
+ | BLT_BR00_DST_TILING_ENABLE(tiling_mode != I915_TILING_NONE)
+ | BLT_BR00_DWORD_LENGTH(6),
+
+ BLT_BR01_CLIPPING_ENABLE(false)
+ | BLT_BR01_MONO_SRC_TRANSPARENCY(monochrome_source_transparency)
+ | BLT_BR01_COLOR_DEPTH(BLT_COLOR_DEPTH_32BIT)
+ | BLT_BR01_RASTER_OPERATION(raster_operation)
+ | BLT_BR01_DST_PITCH(tiling_mode == I915_TILING_NONE
+ ? dst_pitch : dst_pitch >> 2),
+
+ /* XXX: No clipping yet */
+ BLT_BR24_CLP_Y1(0)
+ | BLT_BR24_CLP_X1(0),
+
+ BLT_BR25_CLP_Y2(0)
+ | BLT_BR25_CLP_X2(0),
+
+ BLT_BR09_DST_ADDRESS(dst->offset),
+ BLT_BR05_BACKGROUND_COLOR(background_color),
+ BLT_BR06_FOREGROUND_COLOR(foreground_color),
+ BLT_BR07_PAT_ADDRESS(0)
+ );
+}
+
+static inline int xy_text_blt(struct intel_batch * batch,
+ drm_intel_bo * src, uint32_t src_offset,
+ drm_intel_bo * dst,
+ int16_t dst_x1, int16_t dst_y1,
+ int16_t dst_x2, int16_t dst_y2)
+{
+ uint32_t tiling_mode, swizzle_mode;
+
+ if (!intel_batch_check_space(batch, 4))
+ return INTEL_BATCH_NO_SPACE;
+
+ drm_intel_bo_get_tiling(dst, &tiling_mode, &swizzle_mode);
+
+ drm_intel_bo_emit_reloc_fence
+ (batch->bo, intel_batch_offset(batch, 3), src, src_offset,
+ I915_GEM_DOMAIN_RENDER, 0);
+
+ intel_batch_add_dwords(batch, 4,
+ BLT_BR00_CLIENT(INTEL_CLIENT_BLT)
+ | BLT_BR00_OP(BLT_OP_XY_TEXT_BLT)
+ | BLT_BR00_PACKING(BLT_PACKING_BYTE)
+ | BLT_BR00_DST_TILING_ENABLE(tiling_mode != I915_TILING_NONE)
+ | BLT_BR00_DWORD_LENGTH(2),
+
+ BLT_BR22_DST_Y1(dst_y1) | BLT_BR22_DST_X1(dst_x1),
+ BLT_BR23_DST_Y2(dst_y2) | BLT_BR23_DST_X2(dst_x2),
+ BLT_BR12_SRC_ADDRESS(src->offset + src_offset)
+ );
+
+ return INTEL_BATCH_SUCCESS;
+}
+
+static inline int xy_text_immediate_blt(struct intel_batch * batch,
+ drm_intel_bo * dst,
+ int16_t dst_x1, int16_t dst_y1,
+ int16_t dst_x2, int16_t dst_y2,
+ uint16_t count, uint32_t * immediates)
+{
+ /* Round up to the next even number. */
+ uint8_t dwords = (count + 1) & ~1;
+ uint32_t index;
+ uint32_t tiling_mode, swizzle_mode;
+
+ if (!intel_batch_check_space(batch, 3 + dwords))
+ return INTEL_BATCH_NO_SPACE;
+
+ drm_intel_bo_get_tiling(dst, &tiling_mode, &swizzle_mode);
+
+ intel_batch_add_dwords(batch, 3,
+ BLT_BR00_CLIENT(INTEL_CLIENT_BLT)
+ | BLT_BR00_OP(BLT_OP_XY_TEXT_IMMEDIATE_BLT)
+ | BLT_BR00_PACKING(BLT_PACKING_BYTE)
+ | BLT_BR00_DST_TILING_ENABLE(tiling_mode != I915_TILING_NONE)
+ | BLT_BR00_DWORD_LENGTH(1 + dwords),
+
+ BLT_BR22_DST_Y1(dst_y1) | BLT_BR22_DST_X1(dst_x1),
+ BLT_BR23_DST_Y2(dst_y2) | BLT_BR23_DST_X2(dst_x2)
+ );
+
+ for (index = 0; index < count; ++index)
+ intel_batch_add_dword(batch, *immediates++);
+
+ /* From BLT engine documentation:
+ *
+ * The IMMEDIATE_BLT data MUST transfer an even number of doublewords. The
+ * BLT engine will hang if it does not get an even number of doublewords. */
+ if (count & 1)
+ intel_batch_add_dword(batch, 0);
+
+ return INTEL_BATCH_SUCCESS;
+}
+
+static inline void xy_src_copy_blt(struct intel_batch * batch,
+ drm_intel_bo * src, uint16_t src_pitch,
+ uint16_t src_x, uint16_t src_y,
+ drm_intel_bo * dst, uint16_t dst_pitch,
+ uint16_t dst_x, uint16_t dst_y,
+ uint16_t width, uint16_t height)
+{
+ uint32_t src_tiling_mode, dst_tiling_mode, swizzle;
+
+ intel_batch_ensure_space(batch, 8);
+
+ drm_intel_bo_get_tiling(dst, &dst_tiling_mode, &swizzle);
+ drm_intel_bo_get_tiling(src, &src_tiling_mode, &swizzle);
+
+ drm_intel_bo_emit_reloc_fence
+ (batch->bo, intel_batch_offset(batch, 4), dst, 0,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ drm_intel_bo_emit_reloc_fence
+ (batch->bo, intel_batch_offset(batch, 7), src, 0,
+ I915_GEM_DOMAIN_RENDER, 0);
+
+ intel_batch_add_dwords(batch, 8,
+ BLT_BR00_CLIENT(INTEL_CLIENT_BLT)
+ | BLT_BR00_OP(BLT_OP_XY_SRC_COPY_BLT)
+ | BLT_BR00_32BPP_MASK(BLT_32BPP_MASK_ALPHA | BLT_32BPP_MASK_RGB)
+ | BLT_BR00_SRC_TILING_ENABLE(src_tiling_mode != I915_TILING_NONE)
+ | BLT_BR00_DST_TILING_ENABLE(dst_tiling_mode != I915_TILING_NONE)
+ | BLT_BR00_DWORD_LENGTH(6),
+
+ BLT_BR13_CLIPPING_ENABLE(false)
+ | BLT_BR13_COLOR_DEPTH(BLT_COLOR_DEPTH_32BIT)
+ | BLT_BR13_RASTER_OPERATION(BLT_RASTER_OPERATION_SRC)
+ | BLT_BR13_DST_PITCH(dst_tiling_mode == I915_TILING_NONE
+ ? dst_pitch : dst_pitch >> 2),
+
+ BLT_BR22_DST_Y1(dst_y) | BLT_BR22_DST_X1(dst_x),
+
+ BLT_BR23_DST_Y2(dst_y + height)
+ | BLT_BR23_DST_X2(dst_x + width),
+
+ BLT_BR09_DST_ADDRESS(dst->offset),
+ BLT_BR26_SRC_Y1(src_y) | BLT_BR26_SRC_X1(src_x),
+ BLT_BR11_SRC_PITCH(src_tiling_mode == I915_TILING_NONE
+ ? src_pitch : src_pitch >> 2),
+ BLT_BR12_SRC_ADDRESS(src->offset)
+ );
+}
+
+static inline void xy_color_blt(struct intel_batch * batch,
+ drm_intel_bo * dst, uint16_t dst_pitch,
+ uint16_t dst_x1, uint16_t dst_y1,
+ uint16_t dst_x2, uint16_t dst_y2,
+ uint32_t color)
+{
+ uint32_t tiling_mode, swizzle_mode;
+
+ intel_batch_ensure_space(batch, 6);
+
+ drm_intel_bo_get_tiling(dst, &tiling_mode, &swizzle_mode);
+
+ drm_intel_bo_emit_reloc_fence
+ (batch->bo, intel_batch_offset(batch, 4), dst, 0,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+
+ intel_batch_add_dwords(batch, 6,
+ BLT_BR00_CLIENT(INTEL_CLIENT_BLT)
+ | BLT_BR00_OP(BLT_OP_XY_COLOR_BLT)
+ | BLT_BR00_32BPP_MASK(BLT_32BPP_MASK_ALPHA | BLT_32BPP_MASK_RGB)
+ | BLT_BR00_DST_TILING_ENABLE(tiling_mode != I915_TILING_NONE)
+ | BLT_BR00_DWORD_LENGTH(4),
+
+ BLT_BR13_CLIPPING_ENABLE(false)
+ | BLT_BR13_COLOR_DEPTH(BLT_COLOR_DEPTH_32BIT)
+ | BLT_BR13_RASTER_OPERATION(BLT_RASTER_OPERATION_PAT)
+ | BLT_BR13_DST_PITCH(tiling_mode == I915_TILING_NONE
+ ? dst_pitch : dst_pitch >> 2),
+
+ BLT_BR22_DST_Y1(dst_y1) | BLT_BR22_DST_X1(dst_x1),
+ BLT_BR23_DST_Y2(dst_y2) | BLT_BR23_DST_X2(dst_x2),
+ BLT_BR09_DST_ADDRESS(dst->offset),
+ BLT_BR16_COLOR(color)
+ );
+}
+
+#endif
+
diff --git a/src/wld/intel/i965_pci_ids.h b/src/wld/intel/i965_pci_ids.h
new file mode 100644
index 0000000..9d38a4a
--- /dev/null
+++ b/src/wld/intel/i965_pci_ids.h
@@ -0,0 +1,93 @@
+CHIPSET(0x29A2, i965, "Intel(R) 965G")
+CHIPSET(0x2992, i965, "Intel(R) 965Q")
+CHIPSET(0x2982, i965, "Intel(R) 965G")
+CHIPSET(0x2972, i965, "Intel(R) 946GZ")
+CHIPSET(0x2A02, i965, "Intel(R) 965GM")
+CHIPSET(0x2A12, i965, "Intel(R) 965GME/GLE")
+CHIPSET(0x2A42, g4x, "Mobile Intel® GM45 Express Chipset")
+CHIPSET(0x2E02, g4x, "Intel(R) Integrated Graphics Device")
+CHIPSET(0x2E12, g4x, "Intel(R) Q45/Q43")
+CHIPSET(0x2E22, g4x, "Intel(R) G45/G43")
+CHIPSET(0x2E32, g4x, "Intel(R) G41")
+CHIPSET(0x2E42, g4x, "Intel(R) B43")
+CHIPSET(0x2E92, g4x, "Intel(R) B43")
+CHIPSET(0x0042, ilk, "Intel(R) Ironlake Desktop")
+CHIPSET(0x0046, ilk, "Intel(R) Ironlake Mobile")
+CHIPSET(0x0102, snb_gt1, "Intel(R) Sandybridge Desktop")
+CHIPSET(0x0112, snb_gt2, "Intel(R) Sandybridge Desktop")
+CHIPSET(0x0122, snb_gt2, "Intel(R) Sandybridge Desktop")
+CHIPSET(0x0106, snb_gt1, "Intel(R) Sandybridge Mobile")
+CHIPSET(0x0116, snb_gt2, "Intel(R) Sandybridge Mobile")
+CHIPSET(0x0126, snb_gt2, "Intel(R) Sandybridge Mobile")
+CHIPSET(0x010A, snb_gt1, "Intel(R) Sandybridge Server")
+CHIPSET(0x0152, ivb_gt1, "Intel(R) Ivybridge Desktop")
+CHIPSET(0x0162, ivb_gt2, "Intel(R) Ivybridge Desktop")
+CHIPSET(0x0156, ivb_gt1, "Intel(R) Ivybridge Mobile")
+CHIPSET(0x0166, ivb_gt2, "Intel(R) Ivybridge Mobile")
+CHIPSET(0x015a, ivb_gt1, "Intel(R) Ivybridge Server")
+CHIPSET(0x016a, ivb_gt2, "Intel(R) Ivybridge Server")
+CHIPSET(0x0402, hsw_gt1, "Intel(R) Haswell Desktop")
+CHIPSET(0x0412, hsw_gt2, "Intel(R) Haswell Desktop")
+CHIPSET(0x0422, hsw_gt3, "Intel(R) Haswell Desktop")
+CHIPSET(0x0406, hsw_gt1, "Intel(R) Haswell Mobile")
+CHIPSET(0x0416, hsw_gt2, "Intel(R) Haswell Mobile")
+CHIPSET(0x0426, hsw_gt3, "Intel(R) Haswell Mobile")
+CHIPSET(0x040A, hsw_gt1, "Intel(R) Haswell Server")
+CHIPSET(0x041A, hsw_gt2, "Intel(R) Haswell Server")
+CHIPSET(0x042A, hsw_gt3, "Intel(R) Haswell Server")
+CHIPSET(0x040B, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x041B, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x042B, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x040E, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x041E, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x042E, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0C02, hsw_gt1, "Intel(R) Haswell Desktop")
+CHIPSET(0x0C12, hsw_gt2, "Intel(R) Haswell Desktop")
+CHIPSET(0x0C22, hsw_gt3, "Intel(R) Haswell Desktop")
+CHIPSET(0x0C06, hsw_gt1, "Intel(R) Haswell Mobile")
+CHIPSET(0x0C16, hsw_gt2, "Intel(R) Haswell Mobile")
+CHIPSET(0x0C26, hsw_gt3, "Intel(R) Haswell Mobile")
+CHIPSET(0x0C0A, hsw_gt1, "Intel(R) Haswell Server")
+CHIPSET(0x0C1A, hsw_gt2, "Intel(R) Haswell Server")
+CHIPSET(0x0C2A, hsw_gt3, "Intel(R) Haswell Server")
+CHIPSET(0x0C0B, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x0C1B, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x0C2B, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0C0E, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x0C1E, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x0C2E, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0A02, hsw_gt1, "Intel(R) Haswell Desktop")
+CHIPSET(0x0A12, hsw_gt2, "Intel(R) Haswell Desktop")
+CHIPSET(0x0A22, hsw_gt3, "Intel(R) Haswell Desktop")
+CHIPSET(0x0A06, hsw_gt1, "Intel(R) Haswell Mobile")
+CHIPSET(0x0A16, hsw_gt2, "Intel(R) Haswell Mobile")
+CHIPSET(0x0A26, hsw_gt3, "Intel(R) Haswell Mobile")
+CHIPSET(0x0A0A, hsw_gt1, "Intel(R) Haswell Server")
+CHIPSET(0x0A1A, hsw_gt2, "Intel(R) Haswell Server")
+CHIPSET(0x0A2A, hsw_gt3, "Intel(R) Haswell Server")
+CHIPSET(0x0A0B, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x0A1B, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x0A2B, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0A0E, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x0A1E, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x0A2E, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0D02, hsw_gt1, "Intel(R) Haswell Desktop")
+CHIPSET(0x0D12, hsw_gt2, "Intel(R) Haswell Desktop")
+CHIPSET(0x0D22, hsw_gt3, "Intel(R) Haswell Desktop")
+CHIPSET(0x0D06, hsw_gt1, "Intel(R) Haswell Mobile")
+CHIPSET(0x0D16, hsw_gt2, "Intel(R) Haswell Mobile")
+CHIPSET(0x0D26, hsw_gt3, "Intel(R) Haswell Mobile")
+CHIPSET(0x0D0A, hsw_gt1, "Intel(R) Haswell Server")
+CHIPSET(0x0D1A, hsw_gt2, "Intel(R) Haswell Server")
+CHIPSET(0x0D2A, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0D0B, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x0D1B, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x0D2B, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0D0E, hsw_gt1, "Intel(R) Haswell")
+CHIPSET(0x0D1E, hsw_gt2, "Intel(R) Haswell")
+CHIPSET(0x0D2E, hsw_gt3, "Intel(R) Haswell")
+CHIPSET(0x0F31, byt, "Intel(R) Bay Trail")
+CHIPSET(0x0F32, byt, "Intel(R) Bay Trail")
+CHIPSET(0x0F33, byt, "Intel(R) Bay Trail")
+CHIPSET(0x0157, byt, "Intel(R) Bay Trail")
+CHIPSET(0x0155, byt, "Intel(R) Bay Trail")
diff --git a/src/wld/intel/local.mk b/src/wld/intel/local.mk
new file mode 100644
index 0000000..f1ac032
--- /dev/null
+++ b/src/wld/intel/local.mk
@@ -0,0 +1,6 @@
+# wld: intel/local.mk
+
+dir := intel
+
+include common.mk
+
diff --git a/src/wld/intel/mi.h b/src/wld/intel/mi.h
new file mode 100644
index 0000000..5c830c7
--- /dev/null
+++ b/src/wld/intel/mi.h
@@ -0,0 +1,50 @@
+/* wld: intel/mi.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_INTEL_MI_H
+#define WLD_INTEL_MI_H
+
+#define INTEL_CLIENT_MI 0x0
+
+#define MI_OP(opcode) ( \
+ INTEL_CLIENT_MI << 29 /* 31:29 */ \
+ | opcode << 23 /* 28:23 */ \
+)
+
+#define MI_NOOP MI_OP(0x00)
+#define MI_FLUSH MI_OP(0x04)
+#define MI_BATCH_BUFFER_END MI_OP(0x0A)
+
+/* MI_NOOP */
+#define MI_NOOP_IDENTIFICATION_NUMBER(number) (1 << 22 | number)
+
+/* MI_FLUSH */
+#define MI_FLUSH_ENABLE_PROTECTED_MEMORY (1 << 6)
+#define MI_FLUSH_DISABLE_INDIRECT_STATE_POINTERS (1 << 5)
+#define MI_FLUSH_CLEAR_GENERIC_MEDIA_STATE (1 << 4)
+#define MI_FLUSH_RESET_GLOBAL_SNAPSHOT_COUNT (1 << 3)
+#define MI_FLUSH_INHIBIT_RENDER_CACHE_FLUSH (1 << 2)
+#define MI_FLUSH_INVALIDATE_STATE_INSTRUCTION_CACHE (1 << 1)
+
+#endif
+
diff --git a/src/wld/interface/buffer.h b/src/wld/interface/buffer.h
new file mode 100644
index 0000000..03c6ffc
--- /dev/null
+++ b/src/wld/interface/buffer.h
@@ -0,0 +1,33 @@
+/* wld: interface/buffer.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+static bool buffer_map(struct buffer * drawable);
+static bool buffer_unmap(struct buffer * drawable);
+static void buffer_destroy(struct buffer * drawable);
+
+static const struct wld_buffer_impl wld_buffer_impl = {
+ .map = &buffer_map,
+ .unmap = &buffer_unmap,
+ .destroy = &buffer_destroy
+};
+
diff --git a/src/wld/interface/context.h b/src/wld/interface/context.h
new file mode 100644
index 0000000..a40dac1
--- /dev/null
+++ b/src/wld/interface/context.h
@@ -0,0 +1,50 @@
+/* wld: interface/context.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+static struct wld_renderer * context_create_renderer
+ (struct wld_context * context);
+static struct buffer * context_create_buffer
+ (struct wld_context * context,
+ uint32_t width, uint32_t height, uint32_t format, uint32_t flags);
+static struct buffer * context_import_buffer
+ (struct wld_context * context, uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height, uint32_t format, uint32_t pitch);
+#ifdef CONTEXT_IMPLEMENTS_CREATE_SURFACE
+static struct wld_surface * context_create_surface
+ (struct wld_context * context,
+ uint32_t width, uint32_t height, uint32_t format, uint32_t flags);
+#endif
+static void context_destroy(struct wld_context * context);
+
+static const struct wld_context_impl wld_context_impl = {
+ .create_renderer = &context_create_renderer,
+ .create_buffer = &context_create_buffer,
+ .import_buffer = &context_import_buffer,
+#ifdef CONTEXT_IMPLEMENTS_CREATE_SURFACE
+ .create_surface = &context_create_surface,
+#else
+ .create_surface = &default_create_surface,
+#endif
+ .destroy = &context_destroy
+};
+
diff --git a/src/wld/interface/drm.h b/src/wld/interface/drm.h
new file mode 100644
index 0000000..6f815ad
--- /dev/null
+++ b/src/wld/interface/drm.h
@@ -0,0 +1,43 @@
+/* wld: interface/drm.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef DRM_DRIVER_NAME
+# error "You must define DRM_DRIVER_NAME before including interface/drm.h"
+#endif
+
+/* DRM driver */
+static bool driver_device_supported(uint32_t vendor_id, uint32_t device_id);
+static struct wld_context * driver_create_context(int drm_fd);
+
+#define EXPAND(f, x) f(x)
+#define VAR(name) name ## _drm_driver
+#define STRING(name) # name
+const struct drm_driver EXPAND(VAR, DRM_DRIVER_NAME) = {
+ .name = EXPAND(STRING, DRM_DRIVER_NAME),
+ .device_supported = &driver_device_supported,
+ .create_context = &driver_create_context,
+};
+#undef VAR
+#undef STRING
+#undef EXPAND
+
diff --git a/src/wld/interface/renderer.h b/src/wld/interface/renderer.h
new file mode 100644
index 0000000..557b693
--- /dev/null
+++ b/src/wld/interface/renderer.h
@@ -0,0 +1,68 @@
+/* wld: interface/drawable.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+static uint32_t renderer_capabilities(struct wld_renderer * renderer,
+ struct buffer * buffer);
+static bool renderer_set_target(struct wld_renderer * renderer,
+ struct buffer * buffer);
+static void renderer_fill_rectangle(struct wld_renderer * renderer,
+ uint32_t color, int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+static void renderer_copy_rectangle(struct wld_renderer * renderer,
+ struct buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height);
+#ifdef RENDERER_IMPLEMENTS_REGION
+static void renderer_fill_region(struct wld_renderer * base, uint32_t color,
+ pixman_region32_t * region);
+static void renderer_copy_region(struct wld_renderer * base,
+ struct buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ pixman_region32_t * region);
+#endif
+static void renderer_draw_text(struct wld_renderer * renderer,
+ struct font * font, uint32_t color,
+ int32_t x, int32_t y,
+ const char * text, uint32_t length,
+ struct wld_extents * extents);
+static void renderer_flush(struct wld_renderer * renderer);
+static void renderer_destroy(struct wld_renderer * renderer);
+
+static const struct wld_renderer_impl wld_renderer_impl = {
+ .capabilities = &renderer_capabilities,
+ .set_target = &renderer_set_target,
+ .fill_rectangle = &renderer_fill_rectangle,
+ .copy_rectangle = &renderer_copy_rectangle,
+#ifdef RENDERER_IMPLEMENTS_REGION
+ .fill_region = &renderer_fill_region,
+ .copy_region = &renderer_copy_region,
+#else
+ .fill_region = &default_fill_region,
+ .copy_region = &default_copy_region,
+#endif
+ .draw_text = &renderer_draw_text,
+ .flush = &renderer_flush,
+ .destroy = &renderer_destroy
+};
+
diff --git a/src/wld/interface/surface.h b/src/wld/interface/surface.h
new file mode 100644
index 0000000..5e10ada
--- /dev/null
+++ b/src/wld/interface/surface.h
@@ -0,0 +1,41 @@
+/* wld: interface/surface.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+static pixman_region32_t * surface_damage(struct wld_surface * surface,
+ pixman_region32_t * new_damage);
+static struct buffer * surface_back(struct wld_surface * surface);
+static struct buffer * surface_take(struct wld_surface * surface);
+static bool surface_release(struct wld_surface * surface,
+ struct buffer * buffer);
+static bool surface_swap(struct wld_surface * surface);
+static void surface_destroy(struct wld_surface * surface);
+
+static const struct wld_surface_impl wld_surface_impl = {
+ .damage = &surface_damage,
+ .back = &surface_back,
+ .take = &surface_take,
+ .release = &surface_release,
+ .swap = &surface_swap,
+ .destroy = &surface_destroy
+};
+
diff --git a/src/wld/interface/wayland.h b/src/wld/interface/wayland.h
new file mode 100644
index 0000000..f457932
--- /dev/null
+++ b/src/wld/interface/wayland.h
@@ -0,0 +1,41 @@
+/* wld: interface/wayland.h
+ *
+ * Copyright (c) 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_IMPL_NAME
+# error you must define WAYLAND_IMPL_NAME before including interface/wayland.h
+#endif
+
+static struct wayland_context * wayland_create_context
+ (struct wl_display * display, struct wl_event_queue * queue);
+static bool wayland_has_format(struct wld_context * context, uint32_t format);
+
+#define EXPAND(f, x) f(x)
+#define VAR(name) name ## _wayland_impl
+const struct wayland_impl EXPAND(VAR, WAYLAND_IMPL_NAME) = {
+ .create_context = &wayland_create_context,
+ .has_format = &wayland_has_format,
+ //.create_surface = &wayland_create_surface,
+};
+#undef VAR
+#undef EXPAND
+
diff --git a/src/wld/nouveau/g80_2d.xml.h b/src/wld/nouveau/g80_2d.xml.h
new file mode 100644
index 0000000..9ac44a3
--- /dev/null
+++ b/src/wld/nouveau/g80_2d.xml.h
@@ -0,0 +1,547 @@
+#ifndef G80_2D_XML
+#define G80_2D_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/envytools/envytools/
+git clone https://github.com/envytools/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/michael/src/envytools/rnndb/root.xml ( 514 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/copyright.xml ( 6452 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv_mmio.xml ( 7175 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/nvchipsets.xml ( 2759 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/bus/pmc.xml ( 11361 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pbus.xml ( 19778 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/g80_defs.xml ( 18175 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/g80_vm.xml ( 9832 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv_vga.xml ( 13101 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pci.xml ( 17513 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv1_pfifo.xml ( 10542 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv4_pfifo.xml ( 24010 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/g80_pfifo.xml ( 23184 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/gf100_pfifo.xml ( 26735 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_vm.xml ( 8722 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/nv40_pclock.xml ( 1166 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/g80_pclock.xml ( 16434 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/gt215_pclock.xml ( 4960 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/nv10_pvideo.xml ( 2468 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/ptimer.xml ( 2285 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv10_pcounter.xml ( 5914 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv40_pcounter.xml ( 9663 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pmpeg.xml ( 12735 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pvpe.xml ( 703 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/mpeg_fifo.xml ( 2614 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/nv_object.xml ( 15326 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pme.xml ( 5105 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/nv17_ptv.xml ( 457 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pnvio.xml ( 31893 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pvp1.xml ( 2108 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pvp2.xml ( 1615 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/xtensa.xml ( 5390 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/ptherm.xml ( 34788 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/bus/pfuse.xml ( 1158 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/punits.xml ( 4661 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp3/pvld.xml ( 13271 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/falcon.xml ( 17092 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/falcon_crypt.xml ( 3446 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp3/ppdec.xml ( 14150 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp3/pppp.xml ( 8842 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/nv_defs.xml ( 4399 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp3/psec.xml ( 993 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/g84_punk089.xml ( 448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_prmvio.xml ( 651 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv1_pdma.xml ( 5339 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv3_pfb.xml ( 4493 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv10_pfb.xml ( 18821 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv_pfb.xml ( 1135 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/g80_pfb.xml ( 11139 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pffb.xml ( 2712 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pstraps.xml ( 8118 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pcipher.xml ( 3572 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pbsp.xml ( 10610 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/pcopy.xml ( 7877 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/gt215_pcodec.xml ( 449 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/gt215_pkfuse.xml ( 448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/pdaemon.xml ( 19259 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/10e000.xml ( 1185 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/memory/gf100_pbfb.xml ( 3917 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pibus.xml ( 8545 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/gf100_pclock.xml ( 7338 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/memory/gf100_pp2p.xml ( 1949 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pxbar.xml ( 1516 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pmfb.xml ( 3646 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/gf100_pcounter.xml ( 12713 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/pvcomp.xml ( 8687 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/pvenc.xml ( 1416 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/gf119_punk1c3.xml ( 981 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pmedia.xml ( 432 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv1_paudio.xml ( 1862 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/extdev/ad1848.xml ( 5260 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv1_pgraph.xml ( 14207 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv1_2d.xml ( 36532 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_pgraph.xml ( 4004 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_pgraph.xml ( 11327 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/pgraph.xml ( 31568 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/tpc.xml ( 6832 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/mpc.xml ( 6373 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/mp.xml ( 16762 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/pgraph.xml ( 26735 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/hw_blk.xml ( 760 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/ctxctl.xml ( 13155 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/gpc.xml ( 13114 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/tpc.xml ( 22154 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/ppc.xml ( 2131 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/rop.xml ( 5134 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_pdma.xml ( 2290 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv1_pfb.xml ( 4030 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_pcrtc.xml ( 1108 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv1_pram.xml ( 1235 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pchipid.xml ( 493 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv1_pdac.xml ( 4628 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/peeprom.xml ( 702 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_pramdac.xml ( 4419 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/g80_pdisplay.xml ( 39075 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/prm.xml ( 5094 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv_evo.xml ( 10448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv_objects.xml ( 1053 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv_m2mf.xml ( 2691 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_m2mf.xml ( 2783 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_dvd.xml ( 2994 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_3d.xml ( 5197 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_3d.xml ( 17716 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv_3ddefs.xml ( 16390 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv10_3d.xml ( 18416 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv20_3d.xml ( 21096 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv30-40_3d.xml ( 32451 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_2d.xml ( 11440 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_3d.xml ( 65900 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_compute.xml ( 14027 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_3d.xml ( 59845 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gk104_p2mf.xml ( 2376 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_compute.xml ( 11143 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gk104_compute.xml ( 10182 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/me_fifo.xml ( 1685 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/vp1_fifo.xml ( 670 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/cipher_fifo.xml ( 2071 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/gk104_copy.xml ( 3938 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_texture.xml ( 8881 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_shaders.xml ( 9244 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/mpeg_cmd.xml ( 7682 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/extdev/adt7473.xml ( 11411 bytes, from 2014-11-02 20:39:42)
+
+Copyright (C) 2006-2014 by the following authors:
+- Artur Huillet <arthur.huillet@free.fr> (ahuillet)
+- Ben Skeggs (darktama, darktama_)
+- B. R. <koala_br@users.sourceforge.net> (koala_br)
+- Carlos Martin <carlosmn@users.sf.net> (carlosmn)
+- Christoph Bumiller <e0425955@student.tuwien.ac.at> (calim, chrisbmr)
+- Dawid Gajownik <gajownik@users.sf.net> (gajownik)
+- Dmitry Baryshkov
+- Dmitry Eremin-Solenikov <lumag@users.sf.net> (lumag)
+- EdB <edb_@users.sf.net> (edb_)
+- Erik Waling <erikwailing@users.sf.net> (erikwaling)
+- Francisco Jerez <currojerez@riseup.net> (curro)
+- imirkin <imirkin@users.sf.net> (imirkin)
+- jb17bsome <jb17bsome@bellsouth.net> (jb17bsome)
+- Jeremy Kolb <kjeremy@users.sf.net> (kjeremy)
+- Laurent Carlier <lordheavym@gmail.com> (lordheavy)
+- Luca Barbieri <luca@luca-barbieri.com> (lb, lb1)
+- Maarten Maathuis <madman2003@gmail.com> (stillunknown)
+- Marcin Kościelnicki <koriakin@0x04.net> (mwk, koriakin)
+- Mark Carey <mark.carey@gmail.com> (careym)
+- Matthieu Castet <matthieu.castet@parrot.com> (mat-c)
+- nvidiaman <nvidiaman@users.sf.net> (nvidiaman)
+- Patrice Mandin <patmandin@gmail.com> (pmandin, pmdata)
+- Pekka Paalanen <pq@iki.fi> (pq, ppaalanen)
+- Peter Popov <ironpeter@users.sf.net> (ironpeter)
+- Richard Hughes <hughsient@users.sf.net> (hughsient)
+- Rudi Cilibrasi <cilibrar@users.sf.net> (cilibrar)
+- Serge Martin
+- Simon Raffeiner
+- Stephane Loeuillet <leroutier@users.sf.net> (leroutier)
+- Stephane Marchesin <stephane.marchesin@gmail.com> (marcheu)
+- sturmflut <sturmflut@users.sf.net> (sturmflut)
+- Sylvain Munaut <tnt@246tNt.com>
+- Victor Stinner <victor.stinner@haypocalc.com> (haypo)
+- Wladmir van der Laan <laanwj@gmail.com> (miathan6)
+- Younes Manton <younes.m@gmail.com> (ymanton)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+
+
+#define G80_2D_DMA_NOTIFY 0x00000180
+
+#define G80_2D_DMA_DST 0x00000184
+
+#define G80_2D_DMA_SRC 0x00000188
+
+#define G80_2D_DMA_COND 0x0000018c
+
+#define G80_2D_DST_FORMAT 0x00000200
+
+#define G80_2D_DST_LINEAR 0x00000204
+
+#define G80_2D_DST_TILE_MODE 0x00000208
+
+#define G80_2D_DST_DEPTH 0x0000020c
+
+#define G80_2D_DST_LAYER 0x00000210
+
+#define G80_2D_DST_PITCH 0x00000214
+
+#define G80_2D_DST_WIDTH 0x00000218
+
+#define G80_2D_DST_HEIGHT 0x0000021c
+
+#define G80_2D_DST_ADDRESS_HIGH 0x00000220
+
+#define G80_2D_DST_ADDRESS_LOW 0x00000224
+
+#define G80_2D_UNK228 0x00000228
+
+#define GF100_2D_UNK228 0x00000228
+
+#define GF100_2D_UNK22C 0x0000022c
+
+#define G80_2D_SRC_FORMAT 0x00000230
+
+#define G80_2D_SRC_LINEAR 0x00000234
+
+#define G80_2D_SRC_TILE_MODE 0x00000238
+
+#define G80_2D_SRC_DEPTH 0x0000023c
+
+#define G80_2D_SRC_LAYER 0x00000240
+
+#define GF100_2D_UNK0240 0x00000240
+
+#define G80_2D_SRC_PITCH 0x00000244
+#define G80_2D_SRC_PITCH__MAX 0x00040000
+
+#define G80_2D_SRC_WIDTH 0x00000248
+#define G80_2D_SRC_WIDTH__MAX 0x00010000
+
+#define G80_2D_SRC_HEIGHT 0x0000024c
+#define G80_2D_SRC_HEIGHT__MAX 0x00010000
+
+#define G80_2D_SRC_ADDRESS_HIGH 0x00000250
+
+#define G80_2D_SRC_ADDRESS_LOW 0x00000254
+
+#define G80_2D_UNK258 0x00000258
+
+#define GF100_2D_UNK25C 0x0000025c
+
+#define G80_2D_UNK260 0x00000260
+
+#define GF100_2D_SINGLE_GPC 0x00000260
+
+#define G80_2D_COND_ADDRESS_HIGH 0x00000264
+
+#define G80_2D_COND_ADDRESS_LOW 0x00000268
+
+#define G80_2D_COND_MODE 0x0000026c
+#define G80_2D_COND_MODE_NEVER 0x00000000
+#define G80_2D_COND_MODE_ALWAYS 0x00000001
+#define G80_2D_COND_MODE_RES_NON_ZERO 0x00000002
+#define G80_2D_COND_MODE_EQUAL 0x00000003
+#define G80_2D_COND_MODE_NOT_EQUAL 0x00000004
+
+#define GF100_2D_UNK0270(i0) (0x00000270 + 0x4*(i0))
+#define GF100_2D_UNK0270__ESIZE 0x00000004
+#define GF100_2D_UNK0270__LEN 0x00000004
+
+#define G80_2D_CLIP_X 0x00000280
+
+#define G80_2D_CLIP_Y 0x00000284
+
+#define G80_2D_CLIP_W 0x00000288
+
+#define G80_2D_CLIP_H 0x0000028c
+
+#define G80_2D_CLIP_ENABLE 0x00000290
+
+#define G80_2D_COLOR_KEY_FORMAT 0x00000294
+#define G80_2D_COLOR_KEY_FORMAT_16BPP 0x00000000
+#define G80_2D_COLOR_KEY_FORMAT_15BPP 0x00000001
+#define G80_2D_COLOR_KEY_FORMAT_24BPP 0x00000002
+#define G80_2D_COLOR_KEY_FORMAT_30BPP 0x00000003
+#define G80_2D_COLOR_KEY_FORMAT_8BPP 0x00000004
+#define G80_2D_COLOR_KEY_FORMAT_16BPP2 0x00000005
+#define G80_2D_COLOR_KEY_FORMAT_32BPP 0x00000006
+
+#define G80_2D_COLOR_KEY 0x00000298
+
+#define G80_2D_COLOR_KEY_ENABLE 0x0000029c
+
+#define G80_2D_ROP 0x000002a0
+
+#define G80_2D_BETA1 0x000002a4
+#define G80_2D_BETA1_BETA1__MASK 0x7f800000
+#define G80_2D_BETA1_BETA1__SHIFT 23
+
+#define G80_2D_BETA4 0x000002a8
+#define G80_2D_BETA4_B__MASK 0x000000ff
+#define G80_2D_BETA4_B__SHIFT 0
+#define G80_2D_BETA4_G__MASK 0x0000ff00
+#define G80_2D_BETA4_G__SHIFT 8
+#define G80_2D_BETA4_R__MASK 0x00ff0000
+#define G80_2D_BETA4_R__SHIFT 16
+#define G80_2D_BETA4_A__MASK 0xff000000
+#define G80_2D_BETA4_A__SHIFT 24
+
+#define G80_2D_OPERATION 0x000002ac
+#define G80_2D_OPERATION_SRCCOPY_AND 0x00000000
+#define G80_2D_OPERATION_ROP_AND 0x00000001
+#define G80_2D_OPERATION_BLEND 0x00000002
+#define G80_2D_OPERATION_SRCCOPY 0x00000003
+#define G80_2D_OPERATION_ROP 0x00000004
+#define G80_2D_OPERATION_SRCCOPY_PREMULT 0x00000005
+#define G80_2D_OPERATION_BLEND_PREMULT 0x00000006
+
+#define G80_2D_PATTERN_OFFSET 0x000002b0
+#define G80_2D_PATTERN_OFFSET_X__MASK 0x0000003f
+#define G80_2D_PATTERN_OFFSET_X__SHIFT 0
+#define G80_2D_PATTERN_OFFSET_Y__MASK 0x00003f00
+#define G80_2D_PATTERN_OFFSET_Y__SHIFT 8
+
+#define G80_2D_PATTERN_SELECT 0x000002b4
+#define G80_2D_PATTERN_SELECT_BITMAP_8X8 0x00000000
+#define G80_2D_PATTERN_SELECT_BITMAP_64X1 0x00000001
+#define G80_2D_PATTERN_SELECT_BITMAP_1X64 0x00000002
+#define G80_2D_PATTERN_SELECT_COLOR 0x00000003
+
+#define GF100_2D_UNK02B8(i0) (0x000002b8 + 0x4*(i0))
+#define GF100_2D_UNK02B8__ESIZE 0x00000004
+#define GF100_2D_UNK02B8__LEN 0x00000009
+
+#define GF100_2D_UNK2DC 0x000002dc
+
+#define GF100_2D_UNK2E0 0x000002e0
+
+#define GF100_2D_UNK02E4 0x000002e4
+
+#define G80_2D_PATTERN_COLOR_FORMAT 0x000002e8
+#define G80_2D_PATTERN_COLOR_FORMAT_A16R5G6B5 0x00000000
+#define G80_2D_PATTERN_COLOR_FORMAT_X16A1R5G5B5 0x00000001
+#define G80_2D_PATTERN_COLOR_FORMAT_A8R8G8B8 0x00000002
+#define G80_2D_PATTERN_COLOR_FORMAT_X16A8Y8 0x00000003
+#define G80_2D_PATTERN_COLOR_FORMAT_UNK4 0x00000004
+#define G80_2D_PATTERN_COLOR_FORMAT_UNK5 0x00000005
+
+#define G80_2D_PATTERN_BITMAP_FORMAT 0x000002ec
+#define G80_2D_PATTERN_BITMAP_FORMAT_CGA6 0x00000000
+#define G80_2D_PATTERN_BITMAP_FORMAT_LE 0x00000001
+
+#define G80_2D_PATTERN_BITMAP_COLOR(i0) (0x000002f0 + 0x4*(i0))
+#define G80_2D_PATTERN_BITMAP_COLOR__ESIZE 0x00000004
+#define G80_2D_PATTERN_BITMAP_COLOR__LEN 0x00000002
+
+#define G80_2D_PATTERN_BITMAP(i0) (0x000002f8 + 0x4*(i0))
+#define G80_2D_PATTERN_BITMAP__ESIZE 0x00000004
+#define G80_2D_PATTERN_BITMAP__LEN 0x00000002
+
+#define G80_2D_PATTERN_X8R8G8B8(i0) (0x00000300 + 0x4*(i0))
+#define G80_2D_PATTERN_X8R8G8B8__ESIZE 0x00000004
+#define G80_2D_PATTERN_X8R8G8B8__LEN 0x00000040
+#define G80_2D_PATTERN_X8R8G8B8_B__MASK 0x000000ff
+#define G80_2D_PATTERN_X8R8G8B8_B__SHIFT 0
+#define G80_2D_PATTERN_X8R8G8B8_G__MASK 0x0000ff00
+#define G80_2D_PATTERN_X8R8G8B8_G__SHIFT 8
+#define G80_2D_PATTERN_X8R8G8B8_R__MASK 0x00ff0000
+#define G80_2D_PATTERN_X8R8G8B8_R__SHIFT 16
+
+#define G80_2D_PATTERN_R5G6B5(i0) (0x00000400 + 0x4*(i0))
+#define G80_2D_PATTERN_R5G6B5__ESIZE 0x00000004
+#define G80_2D_PATTERN_R5G6B5__LEN 0x00000020
+#define G80_2D_PATTERN_R5G6B5_B0__MASK 0x0000001f
+#define G80_2D_PATTERN_R5G6B5_B0__SHIFT 0
+#define G80_2D_PATTERN_R5G6B5_G0__MASK 0x000007e0
+#define G80_2D_PATTERN_R5G6B5_G0__SHIFT 5
+#define G80_2D_PATTERN_R5G6B5_R0__MASK 0x0000f800
+#define G80_2D_PATTERN_R5G6B5_R0__SHIFT 11
+#define G80_2D_PATTERN_R5G6B5_B1__MASK 0x001f0000
+#define G80_2D_PATTERN_R5G6B5_B1__SHIFT 16
+#define G80_2D_PATTERN_R5G6B5_G1__MASK 0x07e00000
+#define G80_2D_PATTERN_R5G6B5_G1__SHIFT 21
+#define G80_2D_PATTERN_R5G6B5_R1__MASK 0xf8000000
+#define G80_2D_PATTERN_R5G6B5_R1__SHIFT 27
+
+#define G80_2D_PATTERN_X1R5G5B5(i0) (0x00000480 + 0x4*(i0))
+#define G80_2D_PATTERN_X1R5G5B5__ESIZE 0x00000004
+#define G80_2D_PATTERN_X1R5G5B5__LEN 0x00000020
+#define G80_2D_PATTERN_X1R5G5B5_B0__MASK 0x0000001f
+#define G80_2D_PATTERN_X1R5G5B5_B0__SHIFT 0
+#define G80_2D_PATTERN_X1R5G5B5_G0__MASK 0x000003e0
+#define G80_2D_PATTERN_X1R5G5B5_G0__SHIFT 5
+#define G80_2D_PATTERN_X1R5G5B5_R0__MASK 0x00007c00
+#define G80_2D_PATTERN_X1R5G5B5_R0__SHIFT 10
+#define G80_2D_PATTERN_X1R5G5B5_B1__MASK 0x001f0000
+#define G80_2D_PATTERN_X1R5G5B5_B1__SHIFT 16
+#define G80_2D_PATTERN_X1R5G5B5_G1__MASK 0x03e00000
+#define G80_2D_PATTERN_X1R5G5B5_G1__SHIFT 21
+#define G80_2D_PATTERN_X1R5G5B5_R1__MASK 0x7c000000
+#define G80_2D_PATTERN_X1R5G5B5_R1__SHIFT 26
+
+#define G80_2D_PATTERN_Y8(i0) (0x00000500 + 0x4*(i0))
+#define G80_2D_PATTERN_Y8__ESIZE 0x00000004
+#define G80_2D_PATTERN_Y8__LEN 0x00000010
+#define G80_2D_PATTERN_Y8_Y0__MASK 0x000000ff
+#define G80_2D_PATTERN_Y8_Y0__SHIFT 0
+#define G80_2D_PATTERN_Y8_Y1__MASK 0x0000ff00
+#define G80_2D_PATTERN_Y8_Y1__SHIFT 8
+#define G80_2D_PATTERN_Y8_Y2__MASK 0x00ff0000
+#define G80_2D_PATTERN_Y8_Y2__SHIFT 16
+#define G80_2D_PATTERN_Y8_Y3__MASK 0xff000000
+#define G80_2D_PATTERN_Y8_Y3__SHIFT 24
+
+#define GF100_2D_DRAW_COLOR_LONG(i0) (0x00000540 + 0x4*(i0))
+#define GF100_2D_DRAW_COLOR_LONG__ESIZE 0x00000004
+#define GF100_2D_DRAW_COLOR_LONG__LEN 0x00000004
+
+#define G80_2D_DRAW_SHAPE 0x00000580
+#define G80_2D_DRAW_SHAPE_POINTS 0x00000000
+#define G80_2D_DRAW_SHAPE_LINES 0x00000001
+#define G80_2D_DRAW_SHAPE_LINE_STRIP 0x00000002
+#define G80_2D_DRAW_SHAPE_TRIANGLES 0x00000003
+#define G80_2D_DRAW_SHAPE_RECTANGLES 0x00000004
+
+#define G80_2D_DRAW_COLOR_FORMAT 0x00000584
+
+#define G80_2D_DRAW_COLOR 0x00000588
+
+#define G80_2D_UNK58C 0x0000058c
+#define G80_2D_UNK58C_0 0x00000001
+#define G80_2D_UNK58C_1 0x00000010
+#define G80_2D_UNK58C_2 0x00000100
+#define G80_2D_UNK58C_3 0x00001000
+
+#define G80_2D_DRAW_POINT16 0x000005e0
+#define G80_2D_DRAW_POINT16_X__MASK 0x0000ffff
+#define G80_2D_DRAW_POINT16_X__SHIFT 0
+#define G80_2D_DRAW_POINT16_Y__MASK 0xffff0000
+#define G80_2D_DRAW_POINT16_Y__SHIFT 16
+
+#define G80_2D_DRAW_POINT32_X(i0) (0x00000600 + 0x8*(i0))
+#define G80_2D_DRAW_POINT32_X__ESIZE 0x00000008
+#define G80_2D_DRAW_POINT32_X__LEN 0x00000040
+
+#define G80_2D_DRAW_POINT32_Y(i0) (0x00000604 + 0x8*(i0))
+#define G80_2D_DRAW_POINT32_Y__ESIZE 0x00000008
+#define G80_2D_DRAW_POINT32_Y__LEN 0x00000040
+
+#define G80_2D_SIFC_BITMAP_ENABLE 0x00000800
+
+#define G80_2D_SIFC_FORMAT 0x00000804
+
+#define G80_2D_SIFC_BITMAP_FORMAT 0x00000808
+#define G80_2D_SIFC_BITMAP_FORMAT_I1 0x00000000
+#define G80_2D_SIFC_BITMAP_FORMAT_I4 0x00000001
+#define G80_2D_SIFC_BITMAP_FORMAT_I8 0x00000002
+
+#define G80_2D_SIFC_BITMAP_LSB_FIRST 0x0000080c
+
+#define G80_2D_SIFC_BITMAP_LINE_PACK_MODE 0x00000810
+#define G80_2D_SIFC_BITMAP_LINE_PACK_MODE_PACKED 0x00000000
+#define G80_2D_SIFC_BITMAP_LINE_PACK_MODE_ALIGN_BYTE 0x00000001
+#define G80_2D_SIFC_BITMAP_LINE_PACK_MODE_ALIGN_WORD 0x00000002
+
+#define G80_2D_SIFC_BITMAP_COLOR_BIT0 0x00000814
+
+#define G80_2D_SIFC_BITMAP_COLOR_BIT1 0x00000818
+
+#define G80_2D_SIFC_BITMAP_WRITE_BIT0_ENABLE 0x0000081c
+
+#define G80_2D_SIFC_WIDTH 0x00000838
+
+#define G80_2D_SIFC_HEIGHT 0x0000083c
+
+#define G80_2D_SIFC_DX_DU_FRACT 0x00000840
+
+#define G80_2D_SIFC_DX_DU_INT 0x00000844
+
+#define G80_2D_SIFC_DY_DV_FRACT 0x00000848
+
+#define G80_2D_SIFC_DY_DV_INT 0x0000084c
+
+#define G80_2D_SIFC_DST_X_FRACT 0x00000850
+
+#define G80_2D_SIFC_DST_X_INT 0x00000854
+
+#define G80_2D_SIFC_DST_Y_FRACT 0x00000858
+
+#define G80_2D_SIFC_DST_Y_INT 0x0000085c
+
+#define G80_2D_SIFC_DATA 0x00000860
+
+#define G80_2D_UNK0870 0x00000870
+
+#define G80_2D_UNK0880 0x00000880
+
+#define G80_2D_UNK0884 0x00000884
+
+#define G80_2D_UNK0888 0x00000888
+
+#define G80_2D_BLIT_CONTROL 0x0000088c
+#define G80_2D_BLIT_CONTROL_ORIGIN__MASK 0x00000001
+#define G80_2D_BLIT_CONTROL_ORIGIN__SHIFT 0
+#define G80_2D_BLIT_CONTROL_ORIGIN_CENTER 0x00000000
+#define G80_2D_BLIT_CONTROL_ORIGIN_CORNER 0x00000001
+#define G80_2D_BLIT_CONTROL_FILTER__MASK 0x00000010
+#define G80_2D_BLIT_CONTROL_FILTER__SHIFT 4
+#define G80_2D_BLIT_CONTROL_FILTER_POINT_SAMPLE 0x00000000
+#define G80_2D_BLIT_CONTROL_FILTER_BILINEAR 0x00000010
+
+#define G80_2D_BLIT_DST_X 0x000008b0
+
+#define G80_2D_BLIT_DST_Y 0x000008b4
+
+#define G80_2D_BLIT_DST_W 0x000008b8
+
+#define G80_2D_BLIT_DST_H 0x000008bc
+
+#define G80_2D_BLIT_DU_DX_FRACT 0x000008c0
+
+#define G80_2D_BLIT_DU_DX_INT 0x000008c4
+
+#define G80_2D_BLIT_DV_DY_FRACT 0x000008c8
+
+#define G80_2D_BLIT_DV_DY_INT 0x000008cc
+
+#define G80_2D_BLIT_SRC_X_FRACT 0x000008d0
+
+#define G80_2D_BLIT_SRC_X_INT 0x000008d4
+
+#define G80_2D_BLIT_SRC_Y_FRACT 0x000008d8
+
+#define G80_2D_BLIT_SRC_Y_INT 0x000008dc
+
+#define GF100_2D_FIRMWARE(i0) (0x000008e0 + 0x4*(i0))
+#define GF100_2D_FIRMWARE__ESIZE 0x00000004
+#define GF100_2D_FIRMWARE__LEN 0x00000020
+
+
+#endif /* G80_2D_XML */
diff --git a/src/wld/nouveau/g80_defs.xml.h b/src/wld/nouveau/g80_defs.xml.h
new file mode 100644
index 0000000..ba7df43
--- /dev/null
+++ b/src/wld/nouveau/g80_defs.xml.h
@@ -0,0 +1,382 @@
+#ifndef G80_DEFS_XML
+#define G80_DEFS_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/envytools/envytools/
+git clone https://github.com/envytools/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/michael/src/envytools/rnndb/root.xml ( 514 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/copyright.xml ( 6452 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv_mmio.xml ( 7175 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/nvchipsets.xml ( 2759 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/bus/pmc.xml ( 11361 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pbus.xml ( 19778 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/g80_defs.xml ( 18175 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/g80_vm.xml ( 9832 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv_vga.xml ( 13101 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pci.xml ( 17513 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv1_pfifo.xml ( 10542 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv4_pfifo.xml ( 24010 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/g80_pfifo.xml ( 23184 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/gf100_pfifo.xml ( 26735 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_vm.xml ( 8722 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/nv40_pclock.xml ( 1166 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/g80_pclock.xml ( 16434 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/gt215_pclock.xml ( 4960 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/nv10_pvideo.xml ( 2468 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/ptimer.xml ( 2285 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv10_pcounter.xml ( 5914 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv40_pcounter.xml ( 9663 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pmpeg.xml ( 12735 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pvpe.xml ( 703 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/mpeg_fifo.xml ( 2614 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/nv_object.xml ( 15326 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pme.xml ( 5105 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/nv17_ptv.xml ( 457 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pnvio.xml ( 31893 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pvp1.xml ( 2108 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pvp2.xml ( 1615 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/xtensa.xml ( 5390 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/ptherm.xml ( 34788 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/bus/pfuse.xml ( 1158 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/punits.xml ( 4661 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp3/pvld.xml ( 13271 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/falcon.xml ( 17092 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/falcon_crypt.xml ( 3446 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp3/ppdec.xml ( 14150 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp3/pppp.xml ( 8842 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/nv_defs.xml ( 4399 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp3/psec.xml ( 993 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/g84_punk089.xml ( 448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_prmvio.xml ( 651 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv1_pdma.xml ( 5339 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv3_pfb.xml ( 4493 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv10_pfb.xml ( 18821 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv_pfb.xml ( 1135 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/g80_pfb.xml ( 11139 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pffb.xml ( 2712 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pstraps.xml ( 8118 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pcipher.xml ( 3572 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pbsp.xml ( 10610 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/pcopy.xml ( 7877 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/gt215_pcodec.xml ( 449 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/gt215_pkfuse.xml ( 448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/pdaemon.xml ( 19259 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/10e000.xml ( 1185 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/memory/gf100_pbfb.xml ( 3917 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pibus.xml ( 8545 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/gf100_pclock.xml ( 7338 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/memory/gf100_pp2p.xml ( 1949 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pxbar.xml ( 1516 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pmfb.xml ( 3646 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/gf100_pcounter.xml ( 12713 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/pvcomp.xml ( 8687 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/pvenc.xml ( 1416 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/gf119_punk1c3.xml ( 981 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pmedia.xml ( 432 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv1_paudio.xml ( 1862 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/extdev/ad1848.xml ( 5260 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv1_pgraph.xml ( 14207 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv1_2d.xml ( 36532 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_pgraph.xml ( 4004 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_pgraph.xml ( 11327 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/pgraph.xml ( 31568 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/tpc.xml ( 6832 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/mpc.xml ( 6373 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/mp.xml ( 16762 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/pgraph.xml ( 26735 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/hw_blk.xml ( 760 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/ctxctl.xml ( 13155 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/gpc.xml ( 13114 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/tpc.xml ( 22154 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/ppc.xml ( 2131 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/rop.xml ( 5134 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_pdma.xml ( 2290 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv1_pfb.xml ( 4030 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_pcrtc.xml ( 1108 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv1_pram.xml ( 1235 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pchipid.xml ( 493 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv1_pdac.xml ( 4628 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/peeprom.xml ( 702 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_pramdac.xml ( 4419 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/g80_pdisplay.xml ( 39075 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/prm.xml ( 5094 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv_evo.xml ( 10448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv_objects.xml ( 1053 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv_m2mf.xml ( 2691 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_m2mf.xml ( 2783 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_dvd.xml ( 2994 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_3d.xml ( 5197 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_3d.xml ( 17716 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv_3ddefs.xml ( 16390 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv10_3d.xml ( 18416 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv20_3d.xml ( 21096 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv30-40_3d.xml ( 32451 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_2d.xml ( 11440 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_3d.xml ( 65900 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_compute.xml ( 14027 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_3d.xml ( 59845 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gk104_p2mf.xml ( 2376 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_compute.xml ( 11143 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gk104_compute.xml ( 10182 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/me_fifo.xml ( 1685 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/vp1_fifo.xml ( 670 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/cipher_fifo.xml ( 2071 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/gk104_copy.xml ( 3938 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_texture.xml ( 8881 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_shaders.xml ( 9244 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/mpeg_cmd.xml ( 7682 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/extdev/adt7473.xml ( 11411 bytes, from 2014-11-02 20:39:42)
+
+Copyright (C) 2006-2014 by the following authors:
+- Artur Huillet <arthur.huillet@free.fr> (ahuillet)
+- Ben Skeggs (darktama, darktama_)
+- B. R. <koala_br@users.sourceforge.net> (koala_br)
+- Carlos Martin <carlosmn@users.sf.net> (carlosmn)
+- Christoph Bumiller <e0425955@student.tuwien.ac.at> (calim, chrisbmr)
+- Dawid Gajownik <gajownik@users.sf.net> (gajownik)
+- Dmitry Baryshkov
+- Dmitry Eremin-Solenikov <lumag@users.sf.net> (lumag)
+- EdB <edb_@users.sf.net> (edb_)
+- Erik Waling <erikwailing@users.sf.net> (erikwaling)
+- Francisco Jerez <currojerez@riseup.net> (curro)
+- imirkin <imirkin@users.sf.net> (imirkin)
+- jb17bsome <jb17bsome@bellsouth.net> (jb17bsome)
+- Jeremy Kolb <kjeremy@users.sf.net> (kjeremy)
+- Laurent Carlier <lordheavym@gmail.com> (lordheavy)
+- Luca Barbieri <luca@luca-barbieri.com> (lb, lb1)
+- Maarten Maathuis <madman2003@gmail.com> (stillunknown)
+- Marcin Kościelnicki <koriakin@0x04.net> (mwk, koriakin)
+- Mark Carey <mark.carey@gmail.com> (careym)
+- Matthieu Castet <matthieu.castet@parrot.com> (mat-c)
+- nvidiaman <nvidiaman@users.sf.net> (nvidiaman)
+- Patrice Mandin <patmandin@gmail.com> (pmandin, pmdata)
+- Pekka Paalanen <pq@iki.fi> (pq, ppaalanen)
+- Peter Popov <ironpeter@users.sf.net> (ironpeter)
+- Richard Hughes <hughsient@users.sf.net> (hughsient)
+- Rudi Cilibrasi <cilibrar@users.sf.net> (cilibrar)
+- Serge Martin
+- Simon Raffeiner
+- Stephane Loeuillet <leroutier@users.sf.net> (leroutier)
+- Stephane Marchesin <stephane.marchesin@gmail.com> (marcheu)
+- sturmflut <sturmflut@users.sf.net> (sturmflut)
+- Sylvain Munaut <tnt@246tNt.com>
+- Victor Stinner <victor.stinner@haypocalc.com> (haypo)
+- Wladmir van der Laan <laanwj@gmail.com> (miathan6)
+- Younes Manton <younes.m@gmail.com> (ymanton)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define G80_VSTATUS_IDLE 0x00000000
+#define G80_VSTATUS_BUSY 0x00000001
+#define G80_VSTATUS_UNK2 0x00000002
+#define G80_VSTATUS_WAITING 0x00000003
+#define G80_VSTATUS_BLOCKED 0x00000005
+#define G80_VSTATUS_FAULTED 0x00000006
+#define G80_VSTATUS_PAUSED 0x00000007
+#define G80_SURFACE_FORMAT_BITMAP 0x0000001c
+#define G80_SURFACE_FORMAT_UNK1D 0x0000001d
+#define G80_SURFACE_FORMAT_RGBA32_FLOAT 0x000000c0
+#define G80_SURFACE_FORMAT_RGBA32_SINT 0x000000c1
+#define G80_SURFACE_FORMAT_RGBA32_UINT 0x000000c2
+#define G80_SURFACE_FORMAT_RGBX32_FLOAT 0x000000c3
+#define G80_SURFACE_FORMAT_RGBX32_SINT 0x000000c4
+#define G80_SURFACE_FORMAT_RGBX32_UINT 0x000000c5
+#define G80_SURFACE_FORMAT_RGBA16_UNORM 0x000000c6
+#define G80_SURFACE_FORMAT_RGBA16_SNORM 0x000000c7
+#define G80_SURFACE_FORMAT_RGBA16_SINT 0x000000c8
+#define G80_SURFACE_FORMAT_RGBA16_UINT 0x000000c9
+#define G80_SURFACE_FORMAT_RGBA16_FLOAT 0x000000ca
+#define G80_SURFACE_FORMAT_RG32_FLOAT 0x000000cb
+#define G80_SURFACE_FORMAT_RG32_SINT 0x000000cc
+#define G80_SURFACE_FORMAT_RG32_UINT 0x000000cd
+#define G80_SURFACE_FORMAT_RGBX16_FLOAT 0x000000ce
+#define G80_SURFACE_FORMAT_BGRA8_UNORM 0x000000cf
+#define G80_SURFACE_FORMAT_BGRA8_SRGB 0x000000d0
+#define G80_SURFACE_FORMAT_RGB10_A2_UNORM 0x000000d1
+#define G80_SURFACE_FORMAT_RGB10_A2_UINT 0x000000d2
+#define G80_SURFACE_FORMAT_RGBA8_UNORM 0x000000d5
+#define G80_SURFACE_FORMAT_RGBA8_SRGB 0x000000d6
+#define G80_SURFACE_FORMAT_RGBA8_SNORM 0x000000d7
+#define G80_SURFACE_FORMAT_RGBA8_SINT 0x000000d8
+#define G80_SURFACE_FORMAT_RGBA8_UINT 0x000000d9
+#define G80_SURFACE_FORMAT_RG16_UNORM 0x000000da
+#define G80_SURFACE_FORMAT_RG16_SNORM 0x000000db
+#define G80_SURFACE_FORMAT_RG16_SINT 0x000000dc
+#define G80_SURFACE_FORMAT_RG16_UINT 0x000000dd
+#define G80_SURFACE_FORMAT_RG16_FLOAT 0x000000de
+#define G80_SURFACE_FORMAT_BGR10_A2_UNORM 0x000000df
+#define G80_SURFACE_FORMAT_R11G11B10_FLOAT 0x000000e0
+#define G80_SURFACE_FORMAT_R32_SINT 0x000000e3
+#define G80_SURFACE_FORMAT_R32_UINT 0x000000e4
+#define G80_SURFACE_FORMAT_R32_FLOAT 0x000000e5
+#define G80_SURFACE_FORMAT_BGRX8_UNORM 0x000000e6
+#define G80_SURFACE_FORMAT_BGRX8_SRGB 0x000000e7
+#define G80_SURFACE_FORMAT_B5G6R5_UNORM 0x000000e8
+#define G80_SURFACE_FORMAT_BGR5_A1_UNORM 0x000000e9
+#define G80_SURFACE_FORMAT_RG8_UNORM 0x000000ea
+#define G80_SURFACE_FORMAT_RG8_SNORM 0x000000eb
+#define G80_SURFACE_FORMAT_RG8_SINT 0x000000ec
+#define G80_SURFACE_FORMAT_RG8_UINT 0x000000ed
+#define G80_SURFACE_FORMAT_R16_UNORM 0x000000ee
+#define G80_SURFACE_FORMAT_R16_SNORM 0x000000ef
+#define G80_SURFACE_FORMAT_R16_SINT 0x000000f0
+#define G80_SURFACE_FORMAT_R16_UINT 0x000000f1
+#define G80_SURFACE_FORMAT_R16_FLOAT 0x000000f2
+#define G80_SURFACE_FORMAT_R8_UNORM 0x000000f3
+#define G80_SURFACE_FORMAT_R8_SNORM 0x000000f4
+#define G80_SURFACE_FORMAT_R8_SINT 0x000000f5
+#define G80_SURFACE_FORMAT_R8_UINT 0x000000f6
+#define G80_SURFACE_FORMAT_A8_UNORM 0x000000f7
+#define G80_SURFACE_FORMAT_BGR5_X1_UNORM 0x000000f8
+#define G80_SURFACE_FORMAT_RGBX8_UNORM 0x000000f9
+#define G80_SURFACE_FORMAT_RGBX8_SRGB 0x000000fa
+#define G80_SURFACE_FORMAT_BGR5_X1_UNORM_UNKFB 0x000000fb
+#define G80_SURFACE_FORMAT_BGR5_X1_UNORM_UNKFC 0x000000fc
+#define G80_SURFACE_FORMAT_BGRX8_UNORM_UNKFD 0x000000fd
+#define G80_SURFACE_FORMAT_BGRX8_UNORM_UNKFE 0x000000fe
+#define G80_SURFACE_FORMAT_Y32_UINT_UNKFF 0x000000ff
+#define G80_ZETA_FORMAT_Z32_FLOAT 0x0000000a
+#define G80_ZETA_FORMAT_Z16_UNORM 0x00000013
+#define G80_ZETA_FORMAT_S8_Z24_UNORM 0x00000014
+#define G80_ZETA_FORMAT_Z24_X8_UNORM 0x00000015
+#define G80_ZETA_FORMAT_Z24_S8_UNORM 0x00000016
+#define G80_ZETA_FORMAT_Z24_C8_UNORM 0x00000018
+#define G80_ZETA_FORMAT_Z32_S8_X24_FLOAT 0x00000019
+#define G80_ZETA_FORMAT_Z24_X8_S8_C8_X16_UNORM 0x0000001d
+#define G80_ZETA_FORMAT_Z32_X8_C8_X16_FLOAT 0x0000001e
+#define G80_ZETA_FORMAT_Z32_S8_C8_X16_FLOAT 0x0000001f
+#define GK104_IMAGE_FORMAT_RGBA32_FLOAT 0x00000002
+#define GK104_IMAGE_FORMAT_RGBA32_SINT 0x00000003
+#define GK104_IMAGE_FORMAT_RGBA32_UINT 0x00000004
+#define GK104_IMAGE_FORMAT_RGBA16_UNORM 0x00000008
+#define GK104_IMAGE_FORMAT_RGBA16_SNORM 0x00000009
+#define GK104_IMAGE_FORMAT_RGBA16_SINT 0x0000000a
+#define GK104_IMAGE_FORMAT_RGBA16_UINT 0x0000000b
+#define GK104_IMAGE_FORMAT_RGBA16_FLOAT 0x0000000c
+#define GK104_IMAGE_FORMAT_RG32_FLOAT 0x0000000d
+#define GK104_IMAGE_FORMAT_RG32_SINT 0x0000000e
+#define GK104_IMAGE_FORMAT_RG32_UINT 0x0000000f
+#define GK104_IMAGE_FORMAT_RGB10_A2_UNORM 0x00000013
+#define GK104_IMAGE_FORMAT_RGB10_A2_UINT 0x00000015
+#define GK104_IMAGE_FORMAT_RGBA8_UNORM 0x00000018
+#define GK104_IMAGE_FORMAT_RGBA8_SNORM 0x0000001a
+#define GK104_IMAGE_FORMAT_RGBA8_SINT 0x0000001b
+#define GK104_IMAGE_FORMAT_RGBA8_UINT 0x0000001c
+#define GK104_IMAGE_FORMAT_RG16_UNORM 0x0000001d
+#define GK104_IMAGE_FORMAT_RG16_SNORM 0x0000001e
+#define GK104_IMAGE_FORMAT_RG16_SINT 0x0000001f
+#define GK104_IMAGE_FORMAT_RG16_UINT 0x00000020
+#define GK104_IMAGE_FORMAT_RG16_FLOAT 0x00000021
+#define GK104_IMAGE_FORMAT_R11G11B10_FLOAT 0x00000024
+#define GK104_IMAGE_FORMAT_R32_SINT 0x00000027
+#define GK104_IMAGE_FORMAT_R32_UINT 0x00000028
+#define GK104_IMAGE_FORMAT_R32_FLOAT 0x00000029
+#define GK104_IMAGE_FORMAT_RG8_UNORM 0x0000002e
+#define GK104_IMAGE_FORMAT_RG8_SNORM 0x0000002f
+#define GK104_IMAGE_FORMAT_RG8_SINT 0x00000030
+#define GK104_IMAGE_FORMAT_RG8_UINT 0x00000031
+#define GK104_IMAGE_FORMAT_R16_UNORM 0x00000032
+#define GK104_IMAGE_FORMAT_R16_SNORM 0x00000033
+#define GK104_IMAGE_FORMAT_R16_SINT 0x00000034
+#define GK104_IMAGE_FORMAT_R16_UINT 0x00000035
+#define GK104_IMAGE_FORMAT_R16_FLOAT 0x00000036
+#define GK104_IMAGE_FORMAT_R8_UNORM 0x00000037
+#define GK104_IMAGE_FORMAT_R8_SNORM 0x00000038
+#define GK104_IMAGE_FORMAT_R8_SINT 0x00000039
+#define GK104_IMAGE_FORMAT_R8_UINT 0x0000003a
+#define G80_PGRAPH_DATA_ERROR_INVALID_OPERATION 0x00000003
+#define G80_PGRAPH_DATA_ERROR_INVALID_VALUE 0x00000004
+#define G80_PGRAPH_DATA_ERROR_INVALID_ENUM 0x00000005
+#define G80_PGRAPH_DATA_ERROR_INVALID_OBJECT 0x00000008
+#define G80_PGRAPH_DATA_ERROR_READ_ONLY_OBJECT 0x00000009
+#define G80_PGRAPH_DATA_ERROR_SUPERVISOR_OBJECT 0x0000000a
+#define G80_PGRAPH_DATA_ERROR_INVALID_ADDRESS_ALIGNMENT 0x0000000b
+#define G80_PGRAPH_DATA_ERROR_INVALID_BITFIELD 0x0000000c
+#define G80_PGRAPH_DATA_ERROR_BEGIN_END_ACTIVE 0x0000000d
+#define G80_PGRAPH_DATA_ERROR_SEMANTIC_COLOR_BACK_OVER_LIMIT 0x0000000e
+#define G80_PGRAPH_DATA_ERROR_VIEWPORT_ID_NEEDS_GP 0x0000000f
+#define G80_PGRAPH_DATA_ERROR_RT_DOUBLE_BIND 0x00000010
+#define G80_PGRAPH_DATA_ERROR_RT_TYPES_MISMATCH 0x00000011
+#define G80_PGRAPH_DATA_ERROR_RT_LINEAR_WITH_ZETA 0x00000012
+#define G80_PGRAPH_DATA_ERROR_FP_TOO_FEW_REGS 0x00000015
+#define G80_PGRAPH_DATA_ERROR_ZETA_FORMAT_CSAA_MISMATCH 0x00000016
+#define G80_PGRAPH_DATA_ERROR_RT_LINEAR_WITH_MSAA 0x00000017
+#define G80_PGRAPH_DATA_ERROR_FP_INTERPOLANT_START_OVER_LIMIT 0x00000018
+#define G80_PGRAPH_DATA_ERROR_SEMANTIC_LAYER_OVER_LIMIT 0x00000019
+#define G80_PGRAPH_DATA_ERROR_RT_INVALID_ALIGNMENT 0x0000001a
+#define G80_PGRAPH_DATA_ERROR_SAMPLER_OVER_LIMIT 0x0000001b
+#define G80_PGRAPH_DATA_ERROR_TEXTURE_OVER_LIMIT 0x0000001c
+#define G80_PGRAPH_DATA_ERROR_GP_TOO_MANY_OUTPUTS 0x0000001e
+#define G80_PGRAPH_DATA_ERROR_RT_BPP128_WITH_MS8 0x0000001f
+#define G80_PGRAPH_DATA_ERROR_Z_OUT_OF_BOUNDS 0x00000021
+#define G80_PGRAPH_DATA_ERROR_XY_OUT_OF_BOUNDS 0x00000023
+#define G80_PGRAPH_DATA_ERROR_VP_ZERO_INPUTS 0x00000024
+#define G80_PGRAPH_DATA_ERROR_CP_MORE_PARAMS_THAN_SHARED 0x00000027
+#define G80_PGRAPH_DATA_ERROR_CP_NO_REG_SPACE_STRIPED 0x00000028
+#define G80_PGRAPH_DATA_ERROR_CP_NO_REG_SPACE_PACKED 0x00000029
+#define G80_PGRAPH_DATA_ERROR_CP_NOT_ENOUGH_WARPS 0x0000002a
+#define G80_PGRAPH_DATA_ERROR_CP_BLOCK_SIZE_MISMATCH 0x0000002b
+#define G80_PGRAPH_DATA_ERROR_CP_NOT_ENOUGH_LOCAL_WARPS 0x0000002c
+#define G80_PGRAPH_DATA_ERROR_CP_NOT_ENOUGH_STACK_WARPS 0x0000002d
+#define G80_PGRAPH_DATA_ERROR_CP_NO_BLOCKDIM_LATCH 0x0000002e
+#define G80_PGRAPH_DATA_ERROR_ENG2D_FORMAT_MISMATCH 0x00000031
+#define G80_PGRAPH_DATA_ERROR_ENG2D_OPERATION_ILLEGAL_FOR_DST_FORMAT 0x00000033
+#define G80_PGRAPH_DATA_ERROR_ENG2D_FORMAT_MISMATCH_B 0x00000034
+#define G80_PGRAPH_DATA_ERROR_PRIMITIVE_ID_NEEDS_GP 0x0000003f
+#define G80_PGRAPH_DATA_ERROR_SEMANTIC_VIEWPORT_OVER_LIMIT 0x00000044
+#define G80_PGRAPH_DATA_ERROR_SEMANTIC_COLOR_FRONT_OVER_LIMIT 0x00000045
+#define G80_PGRAPH_DATA_ERROR_LAYER_ID_NEEDS_GP 0x00000046
+#define G80_PGRAPH_DATA_ERROR_SEMANTIC_CLIP_OVER_LIMIT 0x00000047
+#define G80_PGRAPH_DATA_ERROR_SEMANTIC_PTSZ_OVER_LIMIT 0x00000048
+#define G80_PGRAPH_DATA_ERROR_M2MF_LINE_LENGTH_EXCEEDS_PITCH_IN 0x00000051
+#define G80_PGRAPH_DATA_ERROR_M2MF_LINE_LENGTH_EXCEEDS_PITCH_OUT 0x00000053
+#define G80_PGRAPH_DATA_ERROR_RT_LINEAR_WITH_ZETA_GF100 0x00000098
+#define G80_PGRAPH_DATA_ERROR_ENG2D_UNALIGNED_PITCH_GF100 0x000000a5
+#define G80_CG_IDLE_TIMEOUT__MASK 0x0000003f
+#define G80_CG_IDLE_TIMEOUT__SHIFT 0
+#define G80_CG_IDLE_TIMEOUT_ENABLE 0x00000040
+#define G80_CG_INTERFACE_REENABLE_TIME__MASK 0x000f0000
+#define G80_CG_INTERFACE_REENABLE_TIME__SHIFT 16
+#define G80_CG_THROTTLE_DUTY_M1__MASK 0x00f00000
+#define G80_CG_THROTTLE_DUTY_M1__SHIFT 20
+#define G80_CG_DELAY__MASK 0x0f000000
+#define G80_CG_DELAY__SHIFT 24
+#define G80_CG_CLOCK_THROTTLE_ENABLE 0x10000000
+#define G80_CG_THROTTLE_MODE__MASK 0x20000000
+#define G80_CG_THROTTLE_MODE__SHIFT 29
+#define G80_CG_THROTTLE_MODE_AUTO 0x00000000
+#define G80_CG_THROTTLE_MODE_MANUAL 0x20000000
+#define G80_CG_INTERFACE_THROTTLE_ENABLE 0x40000000
+#define G80_QUERY__SIZE 0x00000010
+#define G80_QUERY_COUNTER 0x00000000
+
+#define G80_QUERY_RES 0x00000004
+
+#define G80_QUERY_TIME 0x00000008
+
+
+#endif /* G80_DEFS_XML */
diff --git a/src/wld/nouveau/nouveau.c b/src/wld/nouveau/nouveau.c
new file mode 100644
index 0000000..34829eb
--- /dev/null
+++ b/src/wld/nouveau/nouveau.c
@@ -0,0 +1,678 @@
+/* wld: nouveau.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Based in part upon nvc0_exa.c from xf86-video-nouveau, which is:
+ *
+ * Copyright 2007 NVIDIA, Corporation
+ * Copyright 2008 Ben Skeggs
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "drm-private.h"
+#include "drm.h"
+#include "pixman.h"
+#include "nv_object.xml.h"
+#include "g80_2d.xml.h"
+#include "g80_defs.xml.h"
+
+#include <nouveau.h>
+#include <sys/mman.h>
+
+enum nv_architecture
+{
+ NV_ARCH_50 = 0x50,
+ NV_ARCH_C0 = 0xc0,
+ NV_ARCH_E0 = 0xe0
+};
+
+struct nouveau_context
+{
+ struct wld_context base;
+ struct nouveau_device * device;
+ struct nouveau_client * client;
+ enum nv_architecture architecture;
+};
+
+struct nouveau_renderer
+{
+ struct wld_renderer base;
+ struct nouveau_object * channel;
+ struct nouveau_pushbuf * pushbuf;
+ struct nouveau_bufctx * bufctx;
+ struct nouveau_object * nvc0_2d;
+
+ struct nouveau_buffer * target;
+};
+
+struct nouveau_buffer
+{
+ struct buffer base;
+ struct wld_exporter exporter;
+ struct nouveau_context * context;
+ struct nouveau_bo * bo;
+};
+
+#include "interface/context.h"
+#include "interface/renderer.h"
+#include "interface/buffer.h"
+#define DRM_DRIVER_NAME nouveau
+#include "interface/drm.h"
+IMPL(nouveau_context, wld_context)
+IMPL(nouveau_renderer, wld_renderer)
+IMPL(nouveau_buffer, wld_buffer)
+
+/**** DRM driver ****/
+bool driver_device_supported(uint32_t vendor_id, uint32_t device_id)
+{
+ return vendor_id == 0x10de;
+}
+
+struct wld_context * driver_create_context(int drm_fd)
+{
+ struct nouveau_context * context;
+
+ if (!(context = malloc(sizeof *context)))
+ goto error0;
+
+ if (nouveau_device_wrap(drm_fd, 0, &context->device) != 0)
+ goto error1;
+
+ switch (context->device->chipset & ~0xf)
+ {
+ /* TODO: Support NV50
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ context->architecture = NV_ARCH_50;
+ break;
+ */
+ case 0xc0:
+ case 0xd0:
+ context->architecture = NV_ARCH_C0;
+ break;
+ /* TODO: Support NVE0
+ case 0xe0:
+ case 0xf0:
+ case 0x100:
+ context->architecture = NV_ARCH_E0;
+ break;
+ */
+ default:
+ return NULL;
+ }
+
+ if (nouveau_client_new(context->device, &context->client) != 0)
+ goto error2;
+
+ context_initialize(&context->base, &wld_context_impl);
+
+ return &context->base;
+
+ error2:
+ nouveau_device_del(&context->device);
+ error1:
+ free(context);
+ error0:
+ return NULL;
+}
+
+/**** Context ****/
+static inline bool ensure_space(struct nouveau_pushbuf * push, uint32_t count)
+{
+ if (push->end - push->cur > count)
+ return true;
+
+ return nouveau_pushbuf_space(push, count, 0, 0) == 0;
+}
+
+static inline void nv_add_dword(struct nouveau_pushbuf * push, uint32_t dword)
+{
+ *push->cur++ = dword;
+}
+
+static inline void nv_add_dwords_va(struct nouveau_pushbuf * push,
+ uint16_t count, va_list dwords)
+{
+ while (count--)
+ nv_add_dword(push, va_arg(dwords, uint32_t));
+}
+
+static inline void nv_add_data(struct nouveau_pushbuf * push,
+ void * data, uint32_t count)
+{
+ memcpy(push->cur, data, count * 4);
+ push->cur += count;
+}
+
+static inline uint32_t nvc0_format(uint32_t format)
+{
+ switch (format)
+ {
+ case WLD_FORMAT_XRGB8888:
+ return G80_SURFACE_FORMAT_BGRX8_UNORM;
+ case WLD_FORMAT_ARGB8888:
+ return G80_SURFACE_FORMAT_BGRA8_UNORM;
+ }
+
+ return 0;
+}
+
+enum
+{
+ GF100_COMMAND_TYPE_INCREASING = 1,
+ GF100_COMMAND_TYPE_NON_INCREASING = 3,
+ GF100_COMMAND_TYPE_INLINE = 4
+};
+
+enum
+{
+ GF100_SUBCHANNEL_2D = 3,
+};
+
+static inline uint32_t nvc0_command(uint8_t type, uint8_t subchannel,
+ uint16_t method, uint16_t count_or_value)
+{
+ return type << 29 | count_or_value << 16 | subchannel << 13 | method >> 2;
+}
+
+static inline void nvc0_inline(struct nouveau_pushbuf * push,
+ uint8_t subchannel, uint16_t method,
+ uint16_t value)
+{
+ nv_add_dword(push, nvc0_command(GF100_COMMAND_TYPE_INLINE,
+ subchannel, method, value));
+}
+
+static inline void nvc0_methods(struct nouveau_pushbuf * push,
+ uint8_t subchannel, uint16_t start_method,
+ uint16_t count, ...)
+{
+ va_list dwords;
+ nv_add_dword(push, nvc0_command(GF100_COMMAND_TYPE_INCREASING,
+ subchannel, start_method, count));
+ va_start(dwords, count);
+ nv_add_dwords_va(push, count, dwords);
+ va_end(dwords);
+}
+
+#define nvc0_2d(push, method, count, ...) \
+ nvc0_methods(push, GF100_SUBCHANNEL_2D, method, count, __VA_ARGS__)
+#define nvc0_2d_inline(push, method, value) \
+ nvc0_inline(push, GF100_SUBCHANNEL_2D, method, value)
+
+static bool nvc0_2d_initialize(struct nouveau_renderer * renderer)
+{
+ int ret;
+
+ ret = nouveau_object_new(renderer->channel, GF100_2D, GF100_2D, NULL, 0,
+ &renderer->nvc0_2d);
+
+ if (ret != 0)
+ goto error0;
+
+ if (!ensure_space(renderer->pushbuf, 5))
+ goto error1;
+
+ nvc0_2d(renderer->pushbuf, NV1_SUBCHAN_OBJECT, 1,
+ renderer->nvc0_2d->handle);
+ nvc0_2d_inline(renderer->pushbuf, G80_2D_OPERATION,
+ G80_2D_OPERATION_SRCCOPY_AND);
+ nvc0_2d_inline(renderer->pushbuf, G80_2D_UNK0884, 0x3f);
+ nvc0_2d_inline(renderer->pushbuf, G80_2D_UNK0888, 1);
+
+ return true;
+
+ error1:
+ nouveau_object_del(&renderer->nvc0_2d);
+ error0:
+ return false;
+}
+
+static void nvc0_2d_finalize(struct nouveau_renderer * renderer)
+{
+ nouveau_object_del(&renderer->nvc0_2d);
+}
+
+struct wld_renderer * context_create_renderer(struct wld_context * base)
+{
+ struct nouveau_context * context = nouveau_context(base);
+ struct nouveau_renderer * renderer;
+ struct nvc0_fifo fifo = { };
+ int ret;
+
+ if (!(renderer = malloc(sizeof *renderer)))
+ goto error0;
+
+ ret = nouveau_object_new(&context->device->object, 0,
+ NOUVEAU_FIFO_CHANNEL_CLASS, &fifo, sizeof fifo,
+ &renderer->channel);
+
+ if (ret != 0)
+ goto error1;
+
+ ret = nouveau_pushbuf_new(context->client, renderer->channel, 4, 32 * 1024,
+ true, &renderer->pushbuf);
+
+ if (ret != 0)
+ goto error2;
+
+ if (nouveau_bufctx_new(context->client, 1, &renderer->bufctx) != 0)
+ goto error3;
+
+ if (!nvc0_2d_initialize(renderer))
+ goto error4;
+
+ renderer_initialize(&renderer->base, &wld_renderer_impl);
+ renderer->target = NULL;
+
+ return &renderer->base;
+
+ error4:
+ nouveau_bufctx_del(&renderer->bufctx);
+ error3:
+ nouveau_pushbuf_del(&renderer->pushbuf);
+ error2:
+ nouveau_object_del(&renderer->channel);
+ error1:
+ free(renderer);
+ error0:
+ return NULL;
+}
+
+static bool export(struct wld_exporter * exporter, struct wld_buffer * base,
+ uint32_t type, union wld_object * object)
+{
+ struct nouveau_buffer * buffer = nouveau_buffer(base);
+
+ switch (type)
+ {
+ case WLD_DRM_OBJECT_HANDLE:
+ object->u32 = buffer->bo->handle;
+ return true;
+ case WLD_DRM_OBJECT_PRIME_FD:
+ if (nouveau_bo_set_prime(buffer->bo, &object->i) != 0)
+ return false;
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct nouveau_buffer * new_buffer(struct nouveau_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ struct nouveau_buffer * buffer;
+
+ if (!(buffer = malloc(sizeof *buffer)))
+ return NULL;
+
+ buffer_initialize(&buffer->base, &wld_buffer_impl,
+ width, height, format, pitch);
+ buffer->context = context;
+ buffer->exporter.export = &export;
+ wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
+
+ return buffer;
+}
+
+static inline uint32_t roundup(uint32_t value, uint32_t alignment)
+{
+ return (value + alignment - 1) & ~(alignment - 1);
+}
+
+struct buffer * context_create_buffer(struct wld_context * base,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ struct nouveau_context * context = nouveau_context(base);
+ struct nouveau_buffer * buffer;
+ uint32_t bpp = format_bytes_per_pixel(format),
+ pitch = roundup(width * bpp, 64), bo_flags;
+ union nouveau_bo_config config = { };
+
+ if (!(buffer = new_buffer(context, width, height, format, pitch)))
+ goto error0;
+
+ bo_flags = NOUVEAU_BO_VRAM;
+
+ if (flags & WLD_DRM_FLAG_SCANOUT)
+ bo_flags |= NOUVEAU_BO_CONTIG;
+
+ if (height > 0x40 && !(flags & WLD_FLAG_MAP))
+ {
+ config.nvc0.tile_mode = 0x40;
+ config.nvc0.memtype = 0xfe;
+ height = roundup(height, 0x80);
+ }
+ else
+ bo_flags |= NOUVEAU_BO_MAP;
+
+ if (nouveau_bo_new(context->device, bo_flags, 0, pitch * height,
+ &config, &buffer->bo) != 0)
+ {
+ goto error1;
+ }
+
+ return &buffer->base;
+
+ error1:
+ free(buffer);
+ error0:
+ return NULL;
+}
+
+struct buffer * context_import_buffer(struct wld_context * base,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ struct nouveau_context * context = (void *) base;
+ struct nouveau_buffer * buffer;
+ struct nouveau_bo * bo = NULL;
+
+ switch (type)
+ {
+ case WLD_DRM_OBJECT_PRIME_FD:
+ if (nouveau_bo_prime_handle_ref(context->device,
+ object.i, &bo) != 0)
+ {
+ goto error0;
+ }
+ break;
+ default: goto error0;
+ }
+
+ if (!(buffer = new_buffer(context, width, height, format, pitch)))
+ goto error1;
+
+ buffer->bo = bo;
+
+ return &buffer->base;
+
+ error1:
+ nouveau_bo_ref(NULL, &buffer->bo);
+ error0:
+ return NULL;
+}
+
+void context_destroy(struct wld_context * base)
+{
+ struct nouveau_context * context = nouveau_context(base);
+
+ nouveau_client_del(&context->client);
+ nouveau_device_del(&context->device);
+ free(context);
+}
+
+/**** Renderer ****/
+uint32_t renderer_capabilities(struct wld_renderer * renderer,
+ struct buffer * buffer)
+{
+ if (buffer->base.impl == &wld_buffer_impl)
+ return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE;
+
+ return 0;
+}
+
+bool renderer_set_target(struct wld_renderer * base, struct buffer * buffer)
+{
+ struct nouveau_renderer * renderer = nouveau_renderer(base);
+
+ if (buffer && buffer->base.impl != &wld_buffer_impl)
+ return false;
+
+ renderer->target = buffer ? nouveau_buffer(&buffer->base) : NULL;
+
+ return true;
+}
+
+static inline void nvc0_2d_use_buffer(struct nouveau_renderer * renderer,
+ struct nouveau_buffer * buffer,
+ uint16_t format_method, uint16_t format)
+{
+ uint32_t access = format == G80_2D_SRC_FORMAT ? NOUVEAU_BO_RD
+ : NOUVEAU_BO_WR;
+
+ nvc0_2d_inline(renderer->pushbuf, format_method, format);
+
+ if (buffer->bo->config.nvc0.memtype)
+ {
+ nvc0_2d(renderer->pushbuf, format_method + 0x04, 2,
+ 0, buffer->bo->config.nvc0.tile_mode);
+ }
+ else
+ {
+ nvc0_2d_inline(renderer->pushbuf, format_method + 0x04, 1);
+ nvc0_2d(renderer->pushbuf, format_method + 0x14, 1,
+ buffer->base.base.pitch);
+ }
+
+ nvc0_2d(renderer->pushbuf, format_method + 0x18, 4,
+ buffer->base.base.width, buffer->base.base.height,
+ buffer->bo->offset >> 32, buffer->bo->offset);
+ nouveau_bufctx_refn(renderer->bufctx, 0, buffer->bo,
+ NOUVEAU_BO_VRAM | access);
+}
+
+void renderer_fill_rectangle(struct wld_renderer * base, uint32_t color,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct nouveau_renderer * renderer = nouveau_renderer(base);
+ struct nouveau_buffer * dst = renderer->target;
+ uint32_t format;
+
+ if (!ensure_space(renderer->pushbuf, 18))
+ return;
+
+ format = nvc0_format(dst->base.base.format);
+
+ nouveau_bufctx_reset(renderer->bufctx, 0);
+ nvc0_2d_use_buffer(renderer, dst, G80_2D_DST_FORMAT, format);
+ nvc0_2d(renderer->pushbuf, G80_2D_DRAW_SHAPE, 3,
+ G80_2D_DRAW_SHAPE_RECTANGLES, format, color);
+ nouveau_pushbuf_bufctx(renderer->pushbuf, renderer->bufctx);
+
+ if (nouveau_pushbuf_validate(renderer->pushbuf) != 0)
+ return;
+
+ nvc0_2d(renderer->pushbuf, G80_2D_DRAW_POINT32_X(0), 4,
+ x, y, x + width, y + height);
+}
+
+void renderer_copy_rectangle(struct wld_renderer * base,
+ struct buffer * buffer_base,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height)
+{
+ struct nouveau_renderer * renderer = nouveau_renderer(base);
+
+ if (buffer_base->base.impl != &wld_buffer_impl)
+ return;
+
+ struct nouveau_buffer * src = nouveau_buffer(&buffer_base->base),
+ * dst = renderer->target;
+ uint32_t src_format, dst_format;
+
+ if (!ensure_space(renderer->pushbuf, 33))
+ return;
+
+ src_format = nvc0_format(src->base.base.format);
+ dst_format = nvc0_format(dst->base.base.format);
+
+ nouveau_bufctx_reset(renderer->bufctx, 0);
+ nvc0_2d_use_buffer(renderer, src, G80_2D_SRC_FORMAT, src_format);
+ nvc0_2d_use_buffer(renderer, dst, G80_2D_DST_FORMAT, dst_format);
+ nouveau_pushbuf_bufctx(renderer->pushbuf, renderer->bufctx);
+
+ if (nouveau_pushbuf_validate(renderer->pushbuf) != 0)
+ return;
+
+ nvc0_2d_inline(renderer->pushbuf, G80_GRAPH_SERIALIZE, 0);
+ nvc0_2d_inline(renderer->pushbuf, G80_2D_BLIT_CONTROL,
+ G80_2D_BLIT_CONTROL_ORIGIN_CENTER
+ | G80_2D_BLIT_CONTROL_FILTER_POINT_SAMPLE);
+ nvc0_2d(renderer->pushbuf, G80_2D_BLIT_DST_X, 12,
+ dst_x, dst_y, width, height, 0, 1, 0, 1, 0, src_x, 0, src_y);
+
+ renderer_flush(base);
+}
+
+void renderer_draw_text(struct wld_renderer * base,
+ struct font * font, uint32_t color,
+ int32_t x, int32_t y, const char * text,
+ uint32_t length, struct wld_extents * extents)
+{
+ struct nouveau_renderer * renderer = nouveau_renderer(base);
+ struct nouveau_buffer * dst = renderer->target;
+ uint32_t format;
+ int ret;
+ struct glyph * glyph;
+ FT_UInt glyph_index;
+ uint32_t c, count;
+ int32_t origin_x = x;
+
+ if (!ensure_space(renderer->pushbuf, 17))
+ return;
+
+ format = nvc0_format(dst->base.base.format);
+
+ nouveau_bufctx_reset(renderer->bufctx, 0);
+ nvc0_2d_use_buffer(renderer, dst, G80_2D_DST_FORMAT, format);
+ nvc0_2d_inline(renderer->pushbuf, G80_2D_SIFC_BITMAP_ENABLE, 1);
+ nvc0_2d(renderer->pushbuf, G80_2D_SIFC_BITMAP_FORMAT, 6,
+ G80_2D_SIFC_BITMAP_FORMAT_I1,
+ 0, /* SIFC_FORMAT */
+ G80_2D_SIFC_BITMAP_LINE_PACK_MODE_ALIGN_BYTE,
+ 0, color, /* SIFC_BITMAP_COLOR_BIT0, SIFC_BITMAP_COLOR_BIT1 */
+ 0 /* SIFC_BITMAP_WRITE_BIT0_ENABLE */
+ );
+ nouveau_pushbuf_bufctx(renderer->pushbuf, renderer->bufctx);
+
+ if (nouveau_pushbuf_validate(renderer->pushbuf) != 0)
+ return;
+
+ if (length == -1)
+ length = strlen(text);
+
+ while ((ret = FcUtf8ToUcs4((FcChar8 *) text, &c, length)) > 0 && c != '\0')
+ {
+ text += ret;
+ length -= ret;
+ glyph_index = FT_Get_Char_Index(font->face, c);
+
+ if (!font_ensure_glyph(font, glyph_index))
+ continue;
+
+ glyph = font->glyphs[glyph_index];
+
+ if (glyph->bitmap.width == 0 || glyph->bitmap.rows == 0)
+ goto advance;
+
+ count = (glyph->bitmap.pitch * glyph->bitmap.rows + 3) / 4;
+
+ if (!ensure_space(renderer->pushbuf, 12 + count))
+ return;
+
+ nvc0_2d(renderer->pushbuf, G80_2D_SIFC_WIDTH, 10,
+ /* Use the pitch instead of width to ensure the correct
+ * alignment is used. */
+ glyph->bitmap.pitch * 8, glyph->bitmap.rows,
+ 0, 1, 0, 1,
+ 0, origin_x + glyph->x, 0, y + glyph->y);
+ nv_add_dword(renderer->pushbuf,
+ nvc0_command(GF100_COMMAND_TYPE_NON_INCREASING,
+ GF100_SUBCHANNEL_2D,
+ G80_2D_SIFC_DATA, count));
+ nv_add_data(renderer->pushbuf, glyph->bitmap.buffer, count);
+
+ advance:
+ origin_x += glyph->advance;
+ }
+
+ if (extents)
+ extents->advance = origin_x - x;
+}
+
+void renderer_flush(struct wld_renderer * base)
+{
+ struct nouveau_renderer * renderer = nouveau_renderer(base);
+
+ nouveau_pushbuf_kick(renderer->pushbuf, renderer->channel);
+ nouveau_pushbuf_bufctx(renderer->pushbuf, NULL);
+}
+
+void renderer_destroy(struct wld_renderer * base)
+{
+ struct nouveau_renderer * renderer = nouveau_renderer(base);
+
+ nvc0_2d_finalize(renderer);
+ nouveau_bufctx_del(&renderer->bufctx);
+ nouveau_pushbuf_del(&renderer->pushbuf);
+ nouveau_object_del(&renderer->channel);
+ free(renderer);
+}
+
+/**** Buffer ****/
+bool buffer_map(struct buffer * base)
+{
+ struct nouveau_buffer * buffer = nouveau_buffer(&base->base);
+
+ /* If the buffer is tiled, it cannot be mapped into virtual memory in order
+ * to appear linear like intel can do with map_gtt. */
+ if (buffer->bo->config.nvc0.tile_mode)
+ return false;
+
+ if (nouveau_bo_map(buffer->bo, NOUVEAU_BO_WR,
+ buffer->context->client) != 0)
+ {
+ return false;
+ }
+
+ buffer->base.base.map = buffer->bo->map;
+
+ return true;
+}
+
+bool buffer_unmap(struct buffer * base)
+{
+ struct nouveau_buffer * buffer = nouveau_buffer(&base->base);
+
+ if (munmap(buffer->bo->map, buffer->bo->size) == -1)
+ return false;
+
+ buffer->bo->map = NULL;
+ base->base.map = NULL;
+
+ return true;
+}
+
+void buffer_destroy(struct buffer * base)
+{
+ struct nouveau_buffer * buffer = nouveau_buffer(&base->base);
+
+ nouveau_bo_ref(NULL, &buffer->bo);
+ free(buffer);
+}
+
diff --git a/src/wld/nouveau/nv_object.xml.h b/src/wld/nouveau/nv_object.xml.h
new file mode 100644
index 0000000..0a12a19
--- /dev/null
+++ b/src/wld/nouveau/nv_object.xml.h
@@ -0,0 +1,452 @@
+#ifndef NV_OBJECT_XML
+#define NV_OBJECT_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/envytools/envytools/
+git clone https://github.com/envytools/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/michael/src/envytools/rnndb/root.xml ( 514 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/copyright.xml ( 6452 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv_mmio.xml ( 7175 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/nvchipsets.xml ( 2759 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/bus/pmc.xml ( 11361 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pbus.xml ( 19778 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/g80_defs.xml ( 18175 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/g80_vm.xml ( 9832 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv_vga.xml ( 13101 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pci.xml ( 17513 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv1_pfifo.xml ( 10542 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv4_pfifo.xml ( 24010 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/g80_pfifo.xml ( 23184 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/gf100_pfifo.xml ( 26735 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_vm.xml ( 8722 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/nv40_pclock.xml ( 1166 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/g80_pclock.xml ( 16434 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/gt215_pclock.xml ( 4960 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/nv10_pvideo.xml ( 2468 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/ptimer.xml ( 2285 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv10_pcounter.xml ( 5914 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv40_pcounter.xml ( 9663 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pmpeg.xml ( 12735 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pvpe.xml ( 703 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/mpeg_fifo.xml ( 2614 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/nv_object.xml ( 15326 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pme.xml ( 5105 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/nv17_ptv.xml ( 457 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pnvio.xml ( 31893 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/pvp1.xml ( 2108 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pvp2.xml ( 1615 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/xtensa.xml ( 5390 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/ptherm.xml ( 34788 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/bus/pfuse.xml ( 1158 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/punits.xml ( 4661 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp3/pvld.xml ( 13271 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/falcon.xml ( 17092 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/falcon_crypt.xml ( 3446 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp3/ppdec.xml ( 14150 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp3/pppp.xml ( 8842 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/nv_defs.xml ( 4399 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp3/psec.xml ( 993 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/g84_punk089.xml ( 448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_prmvio.xml ( 651 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv1_pdma.xml ( 5339 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv3_pfb.xml ( 4493 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv10_pfb.xml ( 18821 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv_pfb.xml ( 1135 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/g80_pfb.xml ( 11139 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pffb.xml ( 2712 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pstraps.xml ( 8118 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pcipher.xml ( 3572 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/pbsp.xml ( 10610 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/pcopy.xml ( 7877 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/gt215_pcodec.xml ( 449 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/gt215_pkfuse.xml ( 448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/pdaemon.xml ( 19259 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/pm/10e000.xml ( 1185 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/memory/gf100_pbfb.xml ( 3917 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/pibus.xml ( 8545 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/pm/gf100_pclock.xml ( 7338 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/memory/gf100_pp2p.xml ( 1949 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pxbar.xml ( 1516 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/gf100_pmfb.xml ( 3646 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/gf100_pcounter.xml ( 12713 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/pvcomp.xml ( 8687 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/pvenc.xml ( 1416 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/display/gf119_punk1c3.xml ( 981 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pmedia.xml ( 432 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/nv1_paudio.xml ( 1862 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/extdev/ad1848.xml ( 5260 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv1_pgraph.xml ( 14207 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv1_2d.xml ( 36532 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_pgraph.xml ( 4004 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_pgraph.xml ( 11327 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/pgraph.xml ( 31568 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/tpc.xml ( 6832 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/mpc.xml ( 6373 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_pgraph/mp.xml ( 16762 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/pgraph.xml ( 26735 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/hw_blk.xml ( 760 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/ctxctl.xml ( 13155 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/gpc.xml ( 13114 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/tpc.xml ( 22154 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/ppc.xml ( 2131 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_pgraph/rop.xml ( 5134 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_pdma.xml ( 2290 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv1_pfb.xml ( 4030 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_pcrtc.xml ( 1108 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/memory/nv1_pram.xml ( 1235 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/pchipid.xml ( 493 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv1_pdac.xml ( 4628 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/io/peeprom.xml ( 702 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv3_pramdac.xml ( 4419 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/g80_pdisplay.xml ( 39075 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/bus/prm.xml ( 5094 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/display/nv_evo.xml ( 10448 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/fifo/nv_objects.xml ( 1053 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv_m2mf.xml ( 2691 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_m2mf.xml ( 2783 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_dvd.xml ( 2994 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv3_3d.xml ( 5197 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv4_3d.xml ( 17716 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv_3ddefs.xml ( 16390 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv10_3d.xml ( 18416 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv20_3d.xml ( 21096 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/nv30-40_3d.xml ( 32451 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_2d.xml ( 11440 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_3d.xml ( 65900 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_compute.xml ( 14027 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_3d.xml ( 59845 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gk104_p2mf.xml ( 2376 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_compute.xml ( 11143 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gk104_compute.xml ( 10182 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/me_fifo.xml ( 1685 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vpe/vp1_fifo.xml ( 670 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/vdec/vp2/cipher_fifo.xml ( 2071 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/fifo/gk104_copy.xml ( 3938 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/g80_texture.xml ( 8881 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/graph/gf100_shaders.xml ( 9244 bytes, from 2014-11-02 20:39:42)
+- /home/michael/src/envytools/rnndb/vdec/vpe/mpeg_cmd.xml ( 7682 bytes, from 2014-11-02 20:39:43)
+- /home/michael/src/envytools/rnndb/extdev/adt7473.xml ( 11411 bytes, from 2014-11-02 20:39:42)
+
+Copyright (C) 2006-2014 by the following authors:
+- Artur Huillet <arthur.huillet@free.fr> (ahuillet)
+- Ben Skeggs (darktama, darktama_)
+- B. R. <koala_br@users.sourceforge.net> (koala_br)
+- Carlos Martin <carlosmn@users.sf.net> (carlosmn)
+- Christoph Bumiller <e0425955@student.tuwien.ac.at> (calim, chrisbmr)
+- Dawid Gajownik <gajownik@users.sf.net> (gajownik)
+- Dmitry Baryshkov
+- Dmitry Eremin-Solenikov <lumag@users.sf.net> (lumag)
+- EdB <edb_@users.sf.net> (edb_)
+- Erik Waling <erikwailing@users.sf.net> (erikwaling)
+- Francisco Jerez <currojerez@riseup.net> (curro)
+- imirkin <imirkin@users.sf.net> (imirkin)
+- jb17bsome <jb17bsome@bellsouth.net> (jb17bsome)
+- Jeremy Kolb <kjeremy@users.sf.net> (kjeremy)
+- Laurent Carlier <lordheavym@gmail.com> (lordheavy)
+- Luca Barbieri <luca@luca-barbieri.com> (lb, lb1)
+- Maarten Maathuis <madman2003@gmail.com> (stillunknown)
+- Marcin Kościelnicki <koriakin@0x04.net> (mwk, koriakin)
+- Mark Carey <mark.carey@gmail.com> (careym)
+- Matthieu Castet <matthieu.castet@parrot.com> (mat-c)
+- nvidiaman <nvidiaman@users.sf.net> (nvidiaman)
+- Patrice Mandin <patmandin@gmail.com> (pmandin, pmdata)
+- Pekka Paalanen <pq@iki.fi> (pq, ppaalanen)
+- Peter Popov <ironpeter@users.sf.net> (ironpeter)
+- Richard Hughes <hughsient@users.sf.net> (hughsient)
+- Rudi Cilibrasi <cilibrar@users.sf.net> (cilibrar)
+- Serge Martin
+- Simon Raffeiner
+- Stephane Loeuillet <leroutier@users.sf.net> (leroutier)
+- Stephane Marchesin <stephane.marchesin@gmail.com> (marcheu)
+- sturmflut <sturmflut@users.sf.net> (sturmflut)
+- Sylvain Munaut <tnt@246tNt.com>
+- Victor Stinner <victor.stinner@haypocalc.com> (haypo)
+- Wladmir van der Laan <laanwj@gmail.com> (miathan6)
+- Younes Manton <younes.m@gmail.com> (ymanton)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define NV1_DMA_FROM_MEMORY 0x00000002
+#define NV1_DMA_TO_MEMORY 0x00000003
+#define NV1_NULL 0x00000030
+#define NV3_DMA_IN_MEMORY 0x0000003d
+#define NV1_OP_CLIP 0x00000010
+#define NV1_OP_BLEND_AND 0x00000011
+#define NV1_BETA 0x00000012
+#define NV4_BETA4 0x00000072
+#define NV1_OP_ROP_AND 0x00000013
+#define NV1_ROP 0x00000014
+#define NV3_ROP 0x00000043
+#define NV1_OP_CHROMA 0x00000015
+#define NV1_OP_PLANE_SWITCH 0x00000016
+#define NV1_CHROMA 0x00000017
+#define NV4_CHROMA 0x00000057
+#define NV1_PATTERN 0x00000018
+#define NV4_PATTERN 0x00000044
+#define NV1_CLIP 0x00000019
+#define NV1_OP_SRCCOPY_AND 0x00000064
+#define NV3_OP_SRCCOPY 0x00000065
+#define NV4_OP_SRCCOPY_PREMULT 0x00000066
+#define NV4_OP_BLEND_PREMULT 0x00000067
+#define NV1_POINT 0x0000001a
+#define NV1_LINE 0x0000001b
+#define NV1_LIN 0x0000001c
+#define NV4_LIN 0x0000005c
+#define NV30_LIN 0x0000035c
+#define NV40_LIN 0x0000305c
+#define NV1_TRI 0x0000001d
+#define NV4_TRI 0x0000005d
+#define NV1_RECT 0x0000001e
+#define NV4_RECT 0x0000005e
+#define NV1_BLIT 0x0000001f
+#define NV4_BLIT 0x0000005f
+#define NV15_BLIT 0x0000009f
+#define NV1_IFM 0x00000020
+#define NV1_IFC 0x00000021
+#define NV4_IFC 0x00000061
+#define NV5_IFC 0x00000065
+#define NV10_IFC 0x0000008a
+#define NV30_IFC 0x0000038a
+#define NV40_IFC 0x0000308a
+#define NV1_BITMAP 0x00000022
+#define NV1_ITM 0x00000025
+#define NV3_SIFC 0x00000036
+#define NV4_SIFC 0x00000076
+#define NV5_SIFC 0x00000066
+#define NV30_SIFC 0x00000366
+#define NV40_SIFC 0x00003066
+#define NV3_SIFM 0x00000037
+#define NV4_SIFM 0x00000077
+#define NV5_SIFM 0x00000063
+#define NV10_SIFM 0x00000089
+#define NV30_SIFM 0x00000389
+#define NV40_SIFM 0x00003089
+#define G80_SIFM 0x00005089
+#define NV3_GDI 0x0000004b
+#define NV4_GDI 0x0000004a
+#define NV4_SURFACE_SWZ 0x00000052
+#define NV20_SURFACE_SWZ 0x0000009e
+#define NV30_SURFACE_SWZ 0x0000039e
+#define NV40_SURFACE_SWZ 0x0000309e
+#define NV3_SURFACE_DST 0x00000058
+#define NV3_SURFACE_SRC 0x00000059
+#define NV4_SURFACE_2D 0x00000042
+#define NV10_SURFACE_2D 0x00000062
+#define NV30_SURFACE_2D 0x00000362
+#define NV40_SURFACE_2D 0x00003062
+#define G80_SURFACE_2D 0x00005062
+#define NV4_INDEX 0x00000060
+#define NV5_INDEX 0x00000064
+#define NV30_INDEX 0x00000364
+#define NV40_INDEX 0x00003064
+#define NV10_TEXUPLOAD 0x0000007b
+#define NV30_TEXUPLOAD 0x0000037b
+#define NV40_TEXUPLOAD 0x0000307b
+#define NV1_TEXLIN 0x00000023
+#define NV1_TEXQUAD 0x00000024
+#define NV1_TEXLINBETA 0x00000034
+#define NV1_TEXQUADBETA 0x00000035
+#define NV4_DVD_SUBPICTURE 0x00000038
+#define NV10_DVD_SUBPICTURE 0x00000088
+#define NV3_M2MF 0x00000039
+#define G80_M2MF 0x00005039
+#define GF100_M2MF 0x00009039
+#define GK104_P2MF 0x0000a040
+#define GK110_P2MF 0x0000a140
+#define NV3_SURFACE_COLOR 0x0000005a
+#define NV3_SURFACE_ZETA 0x0000005b
+#define NV3_TEXTURED_TRIANGLE 0x00000048
+#define NV4_TEXTURED_TRIANGLE 0x00000054
+#define NV10_TEXTURED_TRIANGLE 0x00000094
+#define NV4_SURFACE_3D 0x00000053
+#define NV10_SURFACE_3D 0x00000093
+#define NV4_MULTITEX_TRIANGLE 0x00000055
+#define NV10_MULTITEX_TRIANGLE 0x00000095
+#define NV10_3D 0x00000056
+#define NV15_3D 0x00000096
+#define NV11_3D 0x00000098
+#define NV17_3D 0x00000099
+#define NV20_3D 0x00000097
+#define NV25_3D 0x00000597
+#define NV30_3D 0x00000397
+#define NV35_3D 0x00000497
+#define NV34_3D 0x00000697
+#define NV40_3D 0x00004097
+#define NV44_3D 0x00004497
+#define G80_3D 0x00005097
+#define G84_3D 0x00008297
+#define G200_3D 0x00008397
+#define GT215_3D 0x00008597
+#define MCP89_3D 0x00008697
+#define GF100_3D 0x00009097
+#define GF108_3D 0x00009197
+#define GF110_3D 0x00009297
+#define GK104_3D 0x0000a097
+#define GK110_3D 0x0000a197
+#define GK20A_3D 0x0000a297
+#define GM107_3D 0x0000b097
+#define G80_2D 0x0000502d
+#define GF100_2D 0x0000902d
+#define G80_COMPUTE 0x000050c0
+#define GT215_COMPUTE 0x000085c0
+#define GF100_COMPUTE 0x000090c0
+#define GF110_COMPUTE 0x000091c0
+#define GK104_COMPUTE 0x0000a0c0
+#define GK110_COMPUTE 0x0000a1c0
+#define GM107_COMPUTE 0x0000b0c0
+#define G84_CIPHER 0x000074c1
+#define GK104_COPY 0x0000a0b5
+#define GM107_COPY 0x0000b0b5
+#define NV31_MPEG 0x00003174
+#define G84_MPEG 0x00008274
+#define NV40_ME 0x00004075
+#define NV41_VP1 0x00004176
+#define SUBCHAN__SIZE 0x00008000
+#define NV1_SUBCHAN 0x00000000
+
+#define NV1_SUBCHAN_OBJECT 0x00000000
+
+#define GF100_SUBCHAN_NOP 0x00000008
+
+#define G84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH 0x00000010
+
+#define G84_SUBCHAN_SEMAPHORE_ADDRESS_LOW 0x00000014
+
+#define G84_SUBCHAN_SEMAPHORE_SEQUENCE 0x00000018
+
+#define G84_SUBCHAN_SEMAPHORE_TRIGGER 0x0000001c
+#define G84_SUBCHAN_SEMAPHORE_TRIGGER_ACTION__MASK 0x0000000f
+#define G84_SUBCHAN_SEMAPHORE_TRIGGER_ACTION__SHIFT 0
+#define G84_SUBCHAN_SEMAPHORE_TRIGGER_ACTION_ACQUIRE_EQUAL 0x00000001
+#define G84_SUBCHAN_SEMAPHORE_TRIGGER_ACTION_RELEASE 0x00000002
+#define G84_SUBCHAN_SEMAPHORE_TRIGGER_ACTION_ACQUIRE_GEQUAL 0x00000004
+#define GF100_SUBCHAN_SEMAPHORE_TRIGGER_ACTION_ACQUIRE_MASK 0x00000008
+#define GF100_SUBCHAN_SEMAPHORE_TRIGGER_YIELD 0x00001000
+#define GF100_SUBCHAN_SEMAPHORE_TRIGGER_UNK20 0x00100000
+#define GF100_SUBCHAN_SEMAPHORE_TRIGGER_SHORT 0x01000000
+
+#define G84_SUBCHAN_NOTIFY_INTR 0x00000020
+
+#define G84_SUBCHAN_WRCACHE_FLUSH 0x00000024
+
+#define MCP89_SUBCHAN_UNK28 0x00000028
+
+#define MCP89_SUBCHAN_UNK2C 0x0000002c
+#define MCP89_SUBCHAN_UNK2C_UNK0__MASK 0x0fffffff
+#define MCP89_SUBCHAN_UNK2C_UNK0__SHIFT 0
+#define MCP89_SUBCHAN_UNK2C_UNK28 0x10000000
+#define MCP89_SUBCHAN_UNK2C_UNK29__MASK 0xe0000000
+#define MCP89_SUBCHAN_UNK2C_UNK29__SHIFT 29
+#define MCP89_SUBCHAN_UNK2C_UNK29_UNK0 0x00000000
+#define MCP89_SUBCHAN_UNK2C_UNK29_UNK1 0x20000000
+#define MCP89_SUBCHAN_UNK2C_UNK29_UNK2 0x40000000
+
+#define NV10_SUBCHAN_REF_CNT 0x00000050
+
+#define NV1A_SUBCHAN_DMA_SEMAPHORE 0x00000060
+
+#define NV1A_SUBCHAN_SEMAPHORE_OFFSET 0x00000064
+
+#define NV1A_SUBCHAN_SEMAPHORE_ACQUIRE 0x00000068
+
+#define NV1A_SUBCHAN_SEMAPHORE_RELEASE 0x0000006c
+
+#define GF100_SUBCHAN_UNK70 0x00000070
+
+#define GF100_SUBCHAN_UNK74 0x00000074
+
+#define GF100_SUBCHAN_UNK78 0x00000078
+
+#define GF100_SUBCHAN_UNK7C 0x0000007c
+
+#define NV40_SUBCHAN_YIELD 0x00000080
+
+#define NV1_GRAPH 0x00000000
+
+#define NV4_GRAPH_NOP 0x00000100
+
+#define NV4_GRAPH_NOTIFY 0x00000104
+#define NV4_GRAPH_NOTIFY_WRITE 0x00000000
+#define NV4_GRAPH_NOTIFY_WRITE_AND_AWAKEN 0x00000001
+
+#define GF100_GRAPH_NOTIFY_ADDRESS_HIGH 0x00000104
+
+#define GF100_GRAPH_NOTIFY_ADDRESS_LOW 0x00000108
+
+#define GF100_GRAPH_NOTIFY 0x0000010c
+#define GF100_GRAPH_NOTIFY_WRITE 0x00000000
+#define GF100_GRAPH_NOTIFY_WRITE_AND_AWAKEN 0x00000001
+
+#define G80_GRAPH_SERIALIZE 0x00000110
+
+#define GF100_GRAPH_MACRO_CODE_POS 0x00000114
+
+#define GF100_GRAPH_MACRO_CODE_DATA 0x00000118
+
+#define GF100_GRAPH_MACRO_ENTRY_POS 0x0000011c
+
+#define GF100_GRAPH_MACRO_ENTRY_DATA 0x00000120
+
+#define GF100_GRAPH_MACRO_UNK0124 0x00000124
+
+#define GT215_GRAPH_UNK0120 0x00000120
+
+#define GT215_GRAPH_UNK0124 0x00000124
+
+#define GF100_GRAPH_COND_MASTER_ADDRESS_HIGH 0x00000130
+
+#define GF100_GRAPH_COND_MASTER_ADDRESS_LOW 0x00000134
+
+#define GF100_GRAPH_COND_MASTER_MODE 0x00000138
+#define GF100_GRAPH_COND_MASTER_MODE_NEVER 0x00000000
+#define GF100_GRAPH_COND_MASTER_MODE_ALWAYS 0x00000001
+#define GF100_GRAPH_COND_MASTER_MODE_RES_NON_ZERO 0x00000002
+#define GF100_GRAPH_COND_MASTER_MODE_EQUAL 0x00000003
+#define GF100_GRAPH_COND_MASTER_MODE_NOT_EQUAL 0x00000004
+
+#define GF100_GRAPH_UNK013C 0x0000013c
+
+#define NV40_GRAPH_PM_TRIGGER 0x00000140
+
+#define GF100_GRAPH_UNK0150 0x00000150
+
+#define GF100_GRAPH_UNK0154 0x00000154
+
+#define GF100_GRAPH_SCRATCH(i0) (0x00003400 + 0x4*(i0))
+#define GF100_GRAPH_SCRATCH__ESIZE 0x00000004
+#define GF100_GRAPH_SCRATCH__LEN 0x00000080
+
+#define GF100_GRAPH_MACRO(i0) (0x00003800 + 0x8*(i0))
+#define GF100_GRAPH_MACRO__ESIZE 0x00000008
+#define GF100_GRAPH_MACRO__LEN 0x00000080
+
+#define GF100_GRAPH_MACRO_PARAM(i0) (0x00003804 + 0x8*(i0))
+#define GF100_GRAPH_MACRO_PARAM__ESIZE 0x00000008
+#define GF100_GRAPH_MACRO_PARAM__LEN 0x00000080
+
+
+#endif /* NV_OBJECT_XML */
diff --git a/src/wld/pixman.c b/src/wld/pixman.c
new file mode 100644
index 0000000..5f14a7b
--- /dev/null
+++ b/src/wld/pixman.c
@@ -0,0 +1,450 @@
+/* wld: pixman.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "pixman.h"
+#include "wld-private.h"
+
+#define PIXMAN_COLOR(c) { \
+ .alpha = ((c >> 24) & 0xff) * 0x101, \
+ .red = ((c >> 16) & 0xff) * 0x101, \
+ .green = ((c >> 8) & 0xff) * 0x101, \
+ .blue = ((c >> 0) & 0xff) * 0x101, \
+}
+
+struct pixman_renderer
+{
+ struct wld_renderer base;
+ pixman_image_t * target;
+ pixman_glyph_cache_t * glyph_cache;
+};
+
+struct pixman_buffer
+{
+ struct buffer base;
+ pixman_image_t * image;
+};
+
+struct pixman_map
+{
+ struct wld_exporter exporter;
+ struct wld_destructor destructor;
+ pixman_image_t * image;
+};
+
+#include "interface/context.h"
+#define RENDERER_IMPLEMENTS_REGION
+#include "interface/renderer.h"
+#include "interface/buffer.h"
+IMPL(pixman_renderer, wld_renderer)
+IMPL(pixman_buffer, wld_buffer)
+
+static struct wld_context context = { .impl = &wld_context_impl };
+
+EXPORT
+struct wld_context * wld_pixman_context = &context;
+
+struct wld_renderer * context_create_renderer(struct wld_context * context)
+{
+ struct pixman_renderer * renderer;
+
+ if (!(renderer = malloc(sizeof *renderer)))
+ goto error0;
+
+ if (!(renderer->glyph_cache = pixman_glyph_cache_create()))
+ goto error1;
+
+ renderer_initialize(&renderer->base, &wld_renderer_impl);
+ renderer->target = NULL;
+
+ return &renderer->base;
+
+ error1:
+ free(renderer);
+ error0:
+ return NULL;
+}
+
+static struct buffer * new_buffer(pixman_image_t * image)
+{
+ struct pixman_buffer * buffer;
+
+ if (!(buffer = malloc(sizeof *buffer)))
+ return NULL;
+
+ buffer_initialize(&buffer->base, &wld_buffer_impl,
+ pixman_image_get_width(image),
+ pixman_image_get_height(image),
+ format_pixman_to_wld(pixman_image_get_format(image)),
+ pixman_image_get_stride(image));
+ buffer->base.base.map = pixman_image_get_data(image);
+ buffer->image = image;
+
+ return &buffer->base;
+}
+
+struct buffer * context_create_buffer(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ struct buffer * buffer;
+ pixman_image_t * image;
+
+ image = pixman_image_create_bits(format_wld_to_pixman(format),
+ width, height, NULL, 0);
+
+ if (!image)
+ goto error0;
+
+ if (!(buffer = new_buffer(image)))
+ goto error1;
+
+ return buffer;
+
+ error1:
+ pixman_image_unref(image);
+ error0:
+ return NULL;
+}
+
+struct buffer * context_import_buffer(struct wld_context * context,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ struct buffer * buffer;
+ pixman_image_t * image;
+
+ switch (type)
+ {
+ case WLD_OBJECT_DATA:
+ image = pixman_image_create_bits(format_wld_to_pixman(format),
+ width, height, object.ptr, pitch);
+ break;
+ default: image = NULL;
+ }
+
+ if (!image)
+ goto error0;
+
+ if (!(buffer = new_buffer(image)))
+ goto error1;
+
+ return buffer;
+
+ error1:
+ pixman_image_unref(image);
+ error0:
+ return NULL;
+
+}
+
+void context_destroy(struct wld_context * context)
+{
+}
+
+uint32_t renderer_capabilities(struct wld_renderer * renderer,
+ struct buffer * buffer)
+{
+ /* The pixman renderer can read and write to any buffer using it's map
+ * implementation. */
+ return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE;
+}
+
+static void destroy_image(pixman_image_t * image, void * data)
+{
+ struct buffer * buffer = data;
+
+ wld_unmap(&buffer->base);
+}
+
+bool map_export(struct wld_exporter * exporter, struct wld_buffer * buffer,
+ uint32_t type, union wld_object * object)
+{
+ struct pixman_map * map
+ = CONTAINER_OF(exporter, struct pixman_map, exporter);
+
+ switch (type)
+ {
+ case WLD_PIXMAN_OBJECT_IMAGE:
+ object->ptr = pixman_image_ref(map->image);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void map_destroy(struct wld_destructor * destructor)
+{
+ struct pixman_map * map
+ = CONTAINER_OF(destructor, struct pixman_map, destructor);
+
+ pixman_image_unref(map->image);
+ free(map);
+}
+
+static pixman_image_t * pixman_image(struct buffer * buffer)
+{
+ if (buffer->base.impl == &wld_buffer_impl)
+ return pixman_image_ref(pixman_buffer(&buffer->base)->image);
+
+ union wld_object object;
+
+ if (wld_export(&buffer->base, WLD_PIXMAN_OBJECT_IMAGE, &object))
+ return object.ptr;
+
+ struct pixman_map * map;
+ pixman_image_t * image;
+
+ if (!wld_map(&buffer->base))
+ goto error0;
+
+ image = pixman_image_create_bits(format_wld_to_pixman(buffer->base.format),
+ buffer->base.width, buffer->base.height,
+ buffer->base.map, buffer->base.pitch);
+
+ if (!image)
+ goto error1;
+
+ if (!(map = malloc(sizeof *map)))
+ goto error2;
+
+ map->image = image;
+ map->exporter.export = &map_export;
+ wld_buffer_add_exporter(&buffer->base, &map->exporter);
+ map->destructor.destroy = &map_destroy;
+ wld_buffer_add_destructor(&buffer->base, &map->destructor);
+ pixman_image_set_destroy_function(image, &destroy_image, buffer);
+
+ return pixman_image_ref(image);
+
+ error2:
+ pixman_image_unref(image);
+ error1:
+ wld_unmap(&buffer->base);
+ error0:
+ return NULL;
+}
+
+bool renderer_set_target(struct wld_renderer * base, struct buffer * buffer)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+
+ if (renderer->target)
+ pixman_image_unref(renderer->target);
+
+ if (buffer)
+ return (renderer->target = pixman_image(buffer));
+
+ renderer->target = NULL;
+ return true;
+}
+
+void renderer_fill_rectangle(struct wld_renderer * base, uint32_t color,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+ pixman_color_t pixman_color = PIXMAN_COLOR(color);
+ pixman_box32_t box = { x, y, x + width, y + height };
+
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target,
+ &pixman_color, 1, &box);
+}
+
+void renderer_fill_region(struct wld_renderer * base, uint32_t color,
+ pixman_region32_t * region)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+ pixman_color_t pixman_color = PIXMAN_COLOR(color);
+ pixman_box32_t * boxes;
+ int num_boxes;
+
+ boxes = pixman_region32_rectangles(region, &num_boxes);
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, renderer->target,
+ &pixman_color, num_boxes, boxes);
+}
+
+void renderer_copy_rectangle(struct wld_renderer * base, struct buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+ pixman_image_t * src = pixman_image(buffer), * dst = renderer->target;
+
+ if (!src) return;
+
+ pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst,
+ src_x, src_y, 0, 0, dst_x, dst_y, width, height);
+}
+
+void renderer_copy_region(struct wld_renderer * base, struct buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ pixman_region32_t * region)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+ pixman_image_t * src = pixman_image(buffer), * dst = renderer->target;
+
+ if (!src) return;
+
+ pixman_image_set_clip_region32(src, region);
+ pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst,
+ region->extents.x1, region->extents.y1, 0, 0,
+ region->extents.x1 + dst_x,
+ region->extents.y1 + dst_y,
+ region->extents.x2 - region->extents.x1,
+ region->extents.y2 - region->extents.y1);
+ pixman_image_set_clip_region32(src, NULL);
+}
+
+static inline uint8_t reverse(uint8_t byte)
+{
+ byte = ((byte << 1) & 0xaa) | ((byte >> 1) & 0x55);
+ byte = ((byte << 2) & 0xcc) | ((byte >> 2) & 0x33);
+ byte = ((byte << 4) & 0xf0) | ((byte >> 4) & 0x0f);
+
+ return byte;
+}
+
+void renderer_draw_text(struct wld_renderer * base,
+ struct font * font, uint32_t color,
+ int32_t x, int32_t y, const char * text,
+ uint32_t length, struct wld_extents * extents)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+ int ret;
+ uint32_t c;
+ struct glyph * glyph;
+ FT_UInt glyph_index;
+ pixman_glyph_t glyphs[length == -1 ? (length = strlen(text)) : length];
+ uint32_t index = 0, origin_x = 0;
+ pixman_color_t pixman_color = PIXMAN_COLOR(color);
+ pixman_image_t * solid;
+
+ solid = pixman_image_create_solid_fill(&pixman_color);
+
+ while ((ret = FcUtf8ToUcs4((FcChar8 *) text, &c, length)) > 0 && c != '\0')
+ {
+ text += ret;
+ length -= ret;
+ glyph_index = FT_Get_Char_Index(font->face, c);
+
+ if (!font_ensure_glyph(font, glyph_index))
+ continue;
+
+ glyph = font->glyphs[glyph_index];
+
+ glyphs[index].x = origin_x;
+ glyphs[index].y = 0;
+ glyphs[index].glyph = pixman_glyph_cache_lookup(renderer->glyph_cache,
+ font, glyph);
+
+ /* If we don't have the glyph in our cache, do some conversions to make
+ * pixman happy, and then insert it. */
+ if (!glyphs[index].glyph)
+ {
+ uint8_t * src, * dst;
+ uint32_t row, byte_index, bytes_per_row, pitch;
+ pixman_image_t * image;
+ FT_Bitmap * bitmap;
+
+ bitmap = &glyph->bitmap;
+ image = pixman_image_create_bits
+ (PIXMAN_a1, bitmap->width, bitmap->rows, NULL, bitmap->pitch);
+
+ if (!image)
+ goto advance;
+
+ pitch = pixman_image_get_stride(image);
+ bytes_per_row = (bitmap->width + 7) / 8;
+ src = bitmap->buffer;
+ dst = (uint8_t *) pixman_image_get_data(image);
+
+ for (row = 0; row < bitmap->rows; ++row)
+ {
+ /* Pixman's A1 format expects the bits in the opposite order
+ * that Freetype gives us. Sigh... */
+ for (byte_index = 0; byte_index < bytes_per_row; ++byte_index)
+ dst[byte_index] = reverse(src[byte_index]);
+
+ dst += pitch;
+ src += bitmap->pitch;
+ }
+
+ /* Insert the glyph into the cache. */
+ pixman_glyph_cache_freeze(renderer->glyph_cache);
+ glyphs[index].glyph = pixman_glyph_cache_insert
+ (renderer->glyph_cache, font, glyph,
+ -glyph->x, -glyph->y, image);
+ pixman_glyph_cache_thaw(renderer->glyph_cache);
+
+ /* The glyph cache copies the contents of the glyph bitmap. */
+ pixman_image_unref(image);
+ }
+
+ ++index;
+
+ advance:
+ origin_x += glyph->advance;
+ }
+
+ pixman_composite_glyphs_no_mask(PIXMAN_OP_OVER, solid, renderer->target,
+ 0, 0, x, y, renderer->glyph_cache,
+ index, glyphs);
+
+ pixman_image_unref(solid);
+
+ if (extents)
+ extents->advance = origin_x;
+}
+
+void renderer_flush(struct wld_renderer * renderer)
+{
+}
+
+void renderer_destroy(struct wld_renderer * base)
+{
+ struct pixman_renderer * renderer = pixman_renderer(base);
+
+ pixman_glyph_cache_destroy(renderer->glyph_cache);
+ free(renderer);
+}
+
+bool buffer_map(struct buffer * buffer)
+{
+ return true;
+}
+
+bool buffer_unmap(struct buffer * buffer)
+{
+ return true;
+}
+
+void buffer_destroy(struct buffer * base)
+{
+ struct pixman_buffer * buffer = pixman_buffer(&base->base);
+
+ pixman_image_unref(buffer->image);
+ free(buffer);
+}
+
diff --git a/src/wld/pixman.h b/src/wld/pixman.h
new file mode 100644
index 0000000..c864385
--- /dev/null
+++ b/src/wld/pixman.h
@@ -0,0 +1,44 @@
+/* wld: pixman.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_PIXMAN_H
+#define WLD_PIXMAN_H
+
+#include <stdint.h>
+
+#define WLD_PIXMAN_ID (0x01 << 24)
+
+enum wld_pixman_object_type
+{
+ WLD_PIXMAN_OBJECT_IMAGE = WLD_PIXMAN_ID
+};
+
+extern struct wld_context * wld_pixman_context;
+
+static inline struct wld_context * wld_pixman_create_context()
+{
+ return wld_pixman_context;
+}
+
+#endif
+
diff --git a/src/wld/protocol/local.mk b/src/wld/protocol/local.mk
new file mode 100644
index 0000000..216a4dd
--- /dev/null
+++ b/src/wld/protocol/local.mk
@@ -0,0 +1,18 @@
+# wld: protocol/local.mk
+
+dir := protocol
+
+PROTOCOL_EXTENSIONS = $(dir)/wayland-drm.xml
+
+$(dir)/%-protocol.c: $(dir)/%.xml
+ $(call quiet,GEN,$(WAYLAND_SCANNER)) code < $< > $@
+
+$(dir)/%-client-protocol.h: $(dir)/%.xml
+ $(call quiet,GEN,$(WAYLAND_SCANNER)) client-header < $< > $@
+
+CLEAN_FILES += \
+ $(PROTOCOL_EXTENSIONS:%.xml=%-protocol.c) \
+ $(PROTOCOL_EXTENSIONS:%.xml=%-client-protocol.h)
+
+include common.mk
+
diff --git a/src/wld/protocol/wayland-drm.xml b/src/wld/protocol/wayland-drm.xml
new file mode 100644
index 0000000..5e64622
--- /dev/null
+++ b/src/wld/protocol/wayland-drm.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="drm">
+
+ <copyright>
+ Copyright © 2008-2011 Kristian Høgsberg
+ Copyright © 2010-2011 Intel Corporation
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that\n the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <!-- drm support. This object is created by the server and published
+ using the display's global event. -->
+ <interface name="wl_drm" version="2">
+ <enum name="error">
+ <entry name="authenticate_fail" value="0"/>
+ <entry name="invalid_format" value="1"/>
+ <entry name="invalid_name" value="2"/>
+ </enum>
+
+ <enum name="format">
+ <!-- The drm format codes match the #defines in drm_fourcc.h.
+ The formats actually supported by the compositor will be
+ reported by the format event. -->
+ <entry name="c8" value="0x20203843"/>
+ <entry name="rgb332" value="0x38424752"/>
+ <entry name="bgr233" value="0x38524742"/>
+ <entry name="xrgb4444" value="0x32315258"/>
+ <entry name="xbgr4444" value="0x32314258"/>
+ <entry name="rgbx4444" value="0x32315852"/>
+ <entry name="bgrx4444" value="0x32315842"/>
+ <entry name="argb4444" value="0x32315241"/>
+ <entry name="abgr4444" value="0x32314241"/>
+ <entry name="rgba4444" value="0x32314152"/>
+ <entry name="bgra4444" value="0x32314142"/>
+ <entry name="xrgb1555" value="0x35315258"/>
+ <entry name="xbgr1555" value="0x35314258"/>
+ <entry name="rgbx5551" value="0x35315852"/>
+ <entry name="bgrx5551" value="0x35315842"/>
+ <entry name="argb1555" value="0x35315241"/>
+ <entry name="abgr1555" value="0x35314241"/>
+ <entry name="rgba5551" value="0x35314152"/>
+ <entry name="bgra5551" value="0x35314142"/>
+ <entry name="rgb565" value="0x36314752"/>
+ <entry name="bgr565" value="0x36314742"/>
+ <entry name="rgb888" value="0x34324752"/>
+ <entry name="bgr888" value="0x34324742"/>
+ <entry name="xrgb8888" value="0x34325258"/>
+ <entry name="xbgr8888" value="0x34324258"/>
+ <entry name="rgbx8888" value="0x34325852"/>
+ <entry name="bgrx8888" value="0x34325842"/>
+ <entry name="argb8888" value="0x34325241"/>
+ <entry name="abgr8888" value="0x34324241"/>
+ <entry name="rgba8888" value="0x34324152"/>
+ <entry name="bgra8888" value="0x34324142"/>
+ <entry name="xrgb2101010" value="0x30335258"/>
+ <entry name="xbgr2101010" value="0x30334258"/>
+ <entry name="rgbx1010102" value="0x30335852"/>
+ <entry name="bgrx1010102" value="0x30335842"/>
+ <entry name="argb2101010" value="0x30335241"/>
+ <entry name="abgr2101010" value="0x30334241"/>
+ <entry name="rgba1010102" value="0x30334152"/>
+ <entry name="bgra1010102" value="0x30334142"/>
+ <entry name="yuyv" value="0x56595559"/>
+ <entry name="yvyu" value="0x55595659"/>
+ <entry name="uyvy" value="0x59565955"/>
+ <entry name="vyuy" value="0x59555956"/>
+ <entry name="ayuv" value="0x56555941"/>
+ <entry name="nv12" value="0x3231564e"/>
+ <entry name="nv21" value="0x3132564e"/>
+ <entry name="nv16" value="0x3631564e"/>
+ <entry name="nv61" value="0x3136564e"/>
+ <entry name="yuv410" value="0x39565559"/>
+ <entry name="yvu410" value="0x39555659"/>
+ <entry name="yuv411" value="0x31315559"/>
+ <entry name="yvu411" value="0x31315659"/>
+ <entry name="yuv420" value="0x32315559"/>
+ <entry name="yvu420" value="0x32315659"/>
+ <entry name="yuv422" value="0x36315559"/>
+ <entry name="yvu422" value="0x36315659"/>
+ <entry name="yuv444" value="0x34325559"/>
+ <entry name="yvu444" value="0x34325659"/>
+ </enum>
+
+ <!-- Call this request with the magic received from drmGetMagic().
+ It will be passed on to the drmAuthMagic() or
+ DRIAuthConnection() call. This authentication must be
+ completed before create_buffer could be used. -->
+ <request name="authenticate">
+ <arg name="id" type="uint"/>
+ </request>
+
+ <!-- Create a wayland buffer for the named DRM buffer. The DRM
+ surface must have a name using the flink ioctl -->
+ <request name="create_buffer">
+ <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="name" type="uint"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="stride" type="uint"/>
+ <arg name="format" type="uint"/>
+ </request>
+
+ <!-- Create a wayland buffer for the named DRM buffer. The DRM
+ surface must have a name using the flink ioctl -->
+ <request name="create_planar_buffer">
+ <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="name" type="uint"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="format" type="uint"/>
+ <arg name="offset0" type="int"/>
+ <arg name="stride0" type="int"/>
+ <arg name="offset1" type="int"/>
+ <arg name="stride1" type="int"/>
+ <arg name="offset2" type="int"/>
+ <arg name="stride2" type="int"/>
+ </request>
+
+ <!-- Notification of the path of the drm device which is used by
+ the server. The client should use this device for creating
+ local buffers. Only buffers created from this device should
+ be be passed to the server using this drm object's
+ create_buffer request. -->
+ <event name="device">
+ <arg name="name" type="string"/>
+ </event>
+
+ <event name="format">
+ <arg name="format" type="uint"/>
+ </event>
+
+ <!-- Raised if the authenticate request succeeded -->
+ <event name="authenticated"/>
+
+ <enum name="capability" since="2">
+ <description summary="wl_drm capability bitmask">
+ Bitmask of capabilities.
+ </description>
+ <entry name="prime" value="1" summary="wl_drm prime available"/>
+ </enum>
+
+ <event name="capabilities">
+ <arg name="value" type="uint"/>
+ </event>
+
+ <!-- Version 2 additions -->
+
+ <!-- Create a wayland buffer for the prime fd. Use for regular and planar
+ buffers. Pass 0 for offset and stride for unused planes. -->
+ <request name="create_prime_buffer" since="2">
+ <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="name" type="fd"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="format" type="uint"/>
+ <arg name="offset0" type="int"/>
+ <arg name="stride0" type="int"/>
+ <arg name="offset1" type="int"/>
+ <arg name="stride1" type="int"/>
+ <arg name="offset2" type="int"/>
+ <arg name="stride2" type="int"/>
+ </request>
+
+ </interface>
+
+</protocol>
diff --git a/src/wld/renderer.c b/src/wld/renderer.c
new file mode 100644
index 0000000..a038095
--- /dev/null
+++ b/src/wld/renderer.c
@@ -0,0 +1,157 @@
+/* wld: renderer.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wld-private.h"
+
+void default_fill_region(struct wld_renderer * renderer, uint32_t color,
+ pixman_region32_t * region)
+{
+ pixman_box32_t * box;
+ int num_boxes;
+
+ box = pixman_region32_rectangles(region, &num_boxes);
+
+ while (num_boxes--)
+ {
+ renderer->impl->fill_rectangle(renderer, color, box->x1, box->y1,
+ box->x2 - box->x1, box->y2 - box->y1);
+ ++box;
+ }
+}
+
+void default_copy_region(struct wld_renderer * renderer, struct buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ pixman_region32_t * region)
+{
+ pixman_box32_t * box;
+ int num_boxes;
+
+ box = pixman_region32_rectangles(region, &num_boxes);
+
+ while (num_boxes--)
+ {
+ renderer->impl->copy_rectangle(renderer, buffer,
+ dst_x + box->x1, dst_y + box->y1,
+ box->x1, box->y1,
+ box->x2 - box->x1, box->y2 - box->y1);
+ ++box;
+ }
+}
+
+void renderer_initialize(struct wld_renderer * renderer,
+ const struct wld_renderer_impl * impl)
+{
+ *((const struct wld_renderer_impl **) &renderer->impl) = impl;
+ renderer->target = NULL;
+}
+
+EXPORT
+void wld_destroy_renderer(struct wld_renderer * renderer)
+{
+ renderer->impl->destroy(renderer);
+}
+
+EXPORT
+uint32_t wld_capabilities(struct wld_renderer * renderer,
+ struct wld_buffer * buffer)
+{
+ return renderer->impl->capabilities(renderer, (struct buffer *) buffer);
+}
+
+EXPORT
+bool wld_set_target_buffer(struct wld_renderer * renderer,
+ struct wld_buffer * buffer)
+{
+ if (!renderer->impl->set_target(renderer, (struct buffer *) buffer))
+ return false;
+
+ renderer->target = buffer;
+
+ return true;
+}
+
+EXPORT
+bool wld_set_target_surface(struct wld_renderer * renderer,
+ struct wld_surface * surface)
+{
+ struct buffer * back_buffer;
+
+ if (!(back_buffer = surface->impl->back(surface)))
+ return false;
+
+ return renderer->impl->set_target(renderer, back_buffer);
+}
+
+EXPORT
+void wld_fill_rectangle(struct wld_renderer * renderer, uint32_t color,
+ int32_t x, int32_t y, uint32_t width, uint32_t height)
+{
+ renderer->impl->fill_rectangle(renderer, color, x, y, width, height);
+}
+
+EXPORT
+void wld_fill_region(struct wld_renderer * renderer, uint32_t color,
+ pixman_region32_t * region)
+{
+ renderer->impl->fill_region(renderer, color, region);
+}
+
+EXPORT
+void wld_copy_rectangle(struct wld_renderer * renderer,
+ struct wld_buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height)
+{
+ renderer->impl->copy_rectangle(renderer, (struct buffer *) buffer,
+ dst_x, dst_y, src_x, src_y, width, height);
+}
+
+EXPORT
+void wld_copy_region(struct wld_renderer * renderer,
+ struct wld_buffer * buffer,
+ int32_t dst_x, int32_t dst_y, pixman_region32_t * region)
+{
+ renderer->impl->copy_region(renderer, (struct buffer *) buffer,
+ dst_x, dst_y, region);
+}
+
+EXPORT
+void wld_draw_text(struct wld_renderer * renderer,
+ struct wld_font * font_base, uint32_t color,
+ int32_t x, int32_t y, const char * text, uint32_t length,
+ struct wld_extents * extents)
+{
+ struct font * font = (void *) font_base;
+
+ renderer->impl->draw_text(renderer, font, color, x, y, text, length,
+ extents);
+}
+
+EXPORT
+void wld_flush(struct wld_renderer * renderer)
+{
+ renderer->impl->flush(renderer);
+ renderer->impl->set_target(renderer, NULL);
+}
+
diff --git a/src/wld/surface.c b/src/wld/surface.c
new file mode 100644
index 0000000..3f936bd
--- /dev/null
+++ b/src/wld/surface.c
@@ -0,0 +1,70 @@
+/* wld: surface.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wld-private.h"
+
+struct wld_surface * default_create_surface(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ return buffered_surface_create(context, width, height, format, flags, NULL);
+}
+
+void surface_initialize(struct wld_surface * surface,
+ const struct wld_surface_impl * impl)
+{
+ *((const struct wld_surface_impl **) &surface->impl) = impl;
+}
+
+EXPORT
+pixman_region32_t * wld_surface_damage(struct wld_surface * surface,
+ pixman_region32_t * new_damage)
+{
+ return surface->impl->damage(surface, new_damage);
+}
+
+EXPORT
+struct wld_buffer * wld_surface_take(struct wld_surface * surface)
+{
+ return &surface->impl->take(surface)->base;
+}
+
+EXPORT
+void wld_surface_release(struct wld_surface * surface,
+ struct wld_buffer * buffer)
+{
+ surface->impl->release(surface, (struct buffer *) buffer);
+}
+
+EXPORT
+bool wld_swap(struct wld_surface * surface)
+{
+ return surface->impl->swap(surface);
+}
+
+EXPORT
+void wld_destroy_surface(struct wld_surface * surface)
+{
+ surface->impl->destroy(surface);
+}
+
diff --git a/src/wld/wayland-drm.c b/src/wld/wayland-drm.c
new file mode 100644
index 0000000..7e7fe4c
--- /dev/null
+++ b/src/wld/wayland-drm.c
@@ -0,0 +1,296 @@
+/* wld: wayland-drm.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wayland.h"
+#include "drm.h"
+#include "wayland-drm-client-protocol.h"
+#include "wayland-private.h"
+#include "wld-private.h"
+#include "drm-private.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <xf86drm.h>
+
+struct drm_context
+{
+ struct wayland_context base;
+ struct wld_context * driver_context;
+ struct wl_drm * wl;
+ struct wl_registry * registry;
+ struct wl_array formats;
+ uint32_t capabilities;
+ int fd;
+ bool authenticated;
+};
+
+#define WAYLAND_IMPL_NAME drm
+#include "interface/context.h"
+#include "interface/wayland.h"
+IMPL(drm_context, wld_context)
+
+static void registry_global(void * data, struct wl_registry * registry,
+ uint32_t name, const char * interface,
+ uint32_t version);
+static void registry_global_remove(void * data, struct wl_registry * registry,
+ uint32_t name);
+
+static void drm_device(void * data, struct wl_drm * wl, const char * name);
+static void drm_format(void * data, struct wl_drm * wl, uint32_t format);
+static void drm_authenticated(void * data, struct wl_drm * wl);
+static void drm_capabilities(void * data, struct wl_drm * wl,
+ uint32_t capabilities);
+
+const static struct wl_registry_listener registry_listener = {
+ .global = &registry_global,
+ .global_remove = &registry_global_remove
+};
+
+const static struct wl_drm_listener drm_listener = {
+ .device = &drm_device,
+ .format = &drm_format,
+ .authenticated = &drm_authenticated,
+ .capabilities = &drm_capabilities
+};
+
+struct wayland_context * wayland_create_context(struct wl_display * display,
+ struct wl_event_queue * queue)
+{
+ struct drm_context * context;
+
+ if (!(context = malloc(sizeof *context)))
+ goto error0;
+
+ context_initialize(&context->base.base, &wld_context_impl);
+ context->wl = NULL;
+ context->fd = -1;
+ context->capabilities = 0;
+ wl_array_init(&context->formats);
+
+ if (!(context->registry = wl_display_get_registry(display)))
+ goto error1;
+
+ wl_registry_add_listener(context->registry, &registry_listener, context);
+ wl_proxy_set_queue((struct wl_proxy *) context->registry, queue);
+
+ /* Wait for wl_drm global. */
+ wl_display_roundtrip_queue(display, queue);
+
+ if (!context->wl)
+ {
+ DEBUG("No wl_drm global\n");
+ goto error2;
+ }
+
+ wl_drm_add_listener(context->wl, &drm_listener, context);
+
+ /* Wait for DRM capabilities and device. */
+ wl_display_roundtrip_queue(display, queue);
+
+ if (!(context->capabilities & WL_DRM_CAPABILITY_PRIME))
+ {
+ DEBUG("No PRIME support\n");
+ goto error3;
+ }
+
+ if (context->fd == -1)
+ {
+ DEBUG("No DRM device\n");
+ goto error3;
+ }
+
+ /* Wait for DRM authentication. */
+ wl_display_roundtrip_queue(display, queue);
+
+ if (!context->authenticated)
+ {
+ DEBUG("DRM authentication failed\n");
+ goto error4;
+ }
+
+ if (!(context->driver_context = wld_drm_create_context(context->fd)))
+ {
+ DEBUG("Couldn't initialize context for DRM device\n");
+ goto error4;
+ }
+
+ return &context->base;
+
+ error4:
+ close(context->fd);
+ error3:
+ wl_drm_destroy(context->wl);
+ error2:
+ wl_registry_destroy(context->registry);
+ error1:
+ wl_array_release(&context->formats);
+ free(context);
+ error0:
+ return NULL;
+}
+
+bool wayland_has_format(struct wld_context * base, uint32_t format)
+{
+ struct drm_context * context = drm_context(base);
+ uint32_t * supported_format;
+
+ wl_array_for_each(supported_format, &context->formats)
+ {
+ if (*supported_format == format)
+ return true;
+ }
+
+ return false;
+}
+
+EXPORT
+int wld_wayland_drm_get_fd(struct wld_context * base)
+{
+ struct drm_context * context = drm_context(base);
+
+ return context->authenticated ? context->fd : -1;
+}
+
+struct wld_renderer * context_create_renderer(struct wld_context * base)
+{
+ struct drm_context * context = drm_context(base);
+
+ return wld_create_renderer(context->driver_context);
+}
+
+struct buffer * context_create_buffer(struct wld_context * base,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ struct drm_context * context = drm_context(base);
+ struct buffer * buffer;
+ union wld_object object;
+ struct wl_buffer * wl;
+
+ if (!wayland_has_format(base, format))
+ goto error0;
+
+ buffer = context->driver_context->impl->create_buffer
+ (context->driver_context, width, height, format, flags);
+
+ if (!buffer)
+ goto error0;
+
+ if (!wld_export(&buffer->base, WLD_DRM_OBJECT_PRIME_FD, &object))
+ goto error1;
+
+ wl = wl_drm_create_prime_buffer(context->wl, object.i, width, height,
+ format, 0, buffer->base.pitch, 0, 0, 0, 0);
+ close(object.i);
+
+ if (!wl)
+ goto error1;
+
+ if (!wayland_buffer_add_exporter(buffer, wl))
+ goto error2;
+
+ return buffer;
+
+ error2:
+ wl_buffer_destroy(wl);
+ error1:
+ wld_buffer_unreference(&buffer->base);
+ error0:
+ return NULL;
+}
+
+struct buffer * context_import_buffer(struct wld_context * context,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ return NULL;
+}
+
+void context_destroy(struct wld_context * base)
+{
+ struct drm_context * context = drm_context(base);
+
+ wld_destroy_context(context->driver_context);
+ close(context->fd);
+ wl_drm_destroy(context->wl);
+ wl_registry_destroy(context->registry);
+ wl_array_release(&context->formats);
+ wl_event_queue_destroy(context->base.queue);
+ free(context);
+}
+
+void registry_global(void * data, struct wl_registry * registry, uint32_t name,
+ const char * interface, uint32_t version)
+{
+ struct drm_context * context = data;
+
+ if (strcmp(interface, "wl_drm") == 0 && version >= 2)
+ context->wl = wl_registry_bind(registry, name, &wl_drm_interface, 2);
+}
+
+void registry_global_remove(void * data, struct wl_registry * registry,
+ uint32_t name)
+{
+}
+
+void drm_device(void * data, struct wl_drm * wl, const char * name)
+{
+ struct drm_context * context = data;
+ drm_magic_t magic;
+
+ context->fd = open(name, O_RDWR);
+
+ if (context->fd == -1)
+ {
+ DEBUG("Couldn't open DRM device '%s'\n", name);
+ return;
+ }
+
+ drmGetMagic(context->fd, &magic);
+ wl_drm_authenticate(wl, magic);
+}
+
+void drm_format(void * data, struct wl_drm * wl, uint32_t format)
+{
+ struct drm_context * context = data;
+
+ *((uint32_t *) wl_array_add(&context->formats, sizeof format)) = format;
+}
+
+void drm_authenticated(void * data, struct wl_drm * wl)
+{
+ struct drm_context * context = data;
+
+ context->authenticated = true;
+}
+
+void drm_capabilities(void * data, struct wl_drm * wl, uint32_t capabilities)
+{
+ struct drm_context * context = data;
+
+ context->capabilities = capabilities;
+}
+
diff --git a/src/wld/wayland-private.h b/src/wld/wayland-private.h
new file mode 100644
index 0000000..f52e3ae
--- /dev/null
+++ b/src/wld/wayland-private.h
@@ -0,0 +1,60 @@
+/* wld: wayland-private.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_WAYLAND_PRIVATE_H
+#define WLD_WAYLAND_PRIVATE_H
+
+#include "wld.h"
+
+struct buffer;
+struct wl_display;
+struct wl_event_queue;
+struct wl_buffer;
+
+struct wayland_context
+{
+ struct wld_context base;
+ const struct wayland_impl * impl;
+ struct wl_display * display;
+ struct wl_event_queue * queue;
+};
+
+struct wayland_impl
+{
+ struct wayland_context * (* create_context)(struct wl_display * display,
+ struct wl_event_queue * queue);
+ bool (* has_format)(struct wld_context * context, uint32_t format);
+};
+
+#if WITH_WAYLAND_DRM
+extern const struct wayland_impl drm_wayland_impl;
+#endif
+
+#if WITH_WAYLAND_SHM
+extern const struct wayland_impl shm_wayland_impl;
+#endif
+
+bool wayland_buffer_add_exporter(struct buffer * buffer, struct wl_buffer * wl);
+
+#endif
+
diff --git a/src/wld/wayland-shm.c b/src/wld/wayland-shm.c
new file mode 100644
index 0000000..520eb2c
--- /dev/null
+++ b/src/wld/wayland-shm.c
@@ -0,0 +1,294 @@
+/* wld: wayland-shm.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE /* Required for mkostemp */
+
+#include "wayland.h"
+#include "wayland-private.h"
+#include "wld-private.h"
+#include "pixman.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <wayland-client.h>
+
+struct shm_context
+{
+ struct wayland_context base;
+ struct wl_registry * registry;
+ struct wl_shm * wl;
+ struct wl_array formats;
+};
+
+struct shm_buffer
+{
+ struct buffer base;
+ int fd;
+};
+
+#define WAYLAND_IMPL_NAME shm
+#include "interface/context.h"
+#include "interface/buffer.h"
+#include "interface/wayland.h"
+IMPL(shm_context, wld_context)
+IMPL(shm_buffer, wld_buffer)
+
+static void registry_global(void * data, struct wl_registry * registry,
+ uint32_t name, const char * interface,
+ uint32_t version);
+static void registry_global_remove(void * data, struct wl_registry * registry,
+ uint32_t name);
+
+static void shm_format(void * data, struct wl_shm * wl, uint32_t format);
+
+const static struct wl_registry_listener registry_listener = {
+ .global = &registry_global,
+ .global_remove = &registry_global_remove
+};
+
+const static struct wl_shm_listener shm_listener = {
+ .format = &shm_format,
+};
+
+static inline uint32_t format_wld_to_shm(uint32_t format)
+{
+ switch (format)
+ {
+ case WLD_FORMAT_ARGB8888:
+ return WL_SHM_FORMAT_ARGB8888;
+ case WLD_FORMAT_XRGB8888:
+ return WL_SHM_FORMAT_XRGB8888;
+ default:
+ return 0;
+ }
+}
+
+struct wayland_context * wayland_create_context(struct wl_display * display,
+ struct wl_event_queue * queue)
+{
+ struct shm_context * context;
+
+ if (!(context = malloc(sizeof *context)))
+ goto error0;
+
+ context_initialize(&context->base.base, &wld_context_impl);
+ context->wl = NULL;
+ wl_array_init(&context->formats);
+
+ if (!(context->registry = wl_display_get_registry(display)))
+ {
+ DEBUG("Couldn't get registry\n");
+ goto error1;
+ }
+
+ wl_registry_add_listener(context->registry, &registry_listener, context);
+ wl_proxy_set_queue((struct wl_proxy *) context->registry, queue);
+
+ /* Wait for wl_shm global. */
+ wl_display_roundtrip_queue(display, queue);
+
+ if (!context->wl)
+ {
+ DEBUG("No wl_shm global\n");
+ goto error2;
+ }
+
+ wl_shm_add_listener(context->wl, &shm_listener, context);
+
+ /* Wait for SHM formats. */
+ wl_display_roundtrip_queue(display, queue);
+
+ return &context->base;
+
+ error2:
+ wl_registry_destroy(context->registry);
+ error1:
+ wl_array_release(&context->formats);
+ free(context);
+ error0:
+ return NULL;
+}
+
+bool wayland_has_format(struct wld_context * base, uint32_t format)
+{
+ struct shm_context * context = shm_context(base);
+ uint32_t * supported_format;
+ uint32_t shm_format = format_wld_to_shm(format);
+
+ wl_array_for_each(supported_format, &context->formats)
+ {
+ if (*supported_format == shm_format)
+ return true;
+ }
+
+ return false;
+}
+
+struct wld_renderer * context_create_renderer(struct wld_context * context)
+{
+ return wld_create_renderer(wld_pixman_context);
+}
+
+struct buffer * context_create_buffer(struct wld_context * base,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags)
+{
+ struct shm_context * context = shm_context(base);
+ struct shm_buffer * buffer;
+ char name[] = "/tmp/wld-XXXXXX";
+ uint32_t pitch = width * format_bytes_per_pixel(format);
+ size_t size = pitch * height;
+ int fd;
+ struct wl_shm_pool * pool;
+ struct wl_buffer * wl;
+
+ if (!wayland_has_format(base, format))
+ goto error0;
+
+ if (!(buffer = malloc(sizeof *buffer)))
+ goto error0;
+
+ fd = mkostemp(name, O_CLOEXEC);
+
+ if (fd < 0)
+ goto error1;
+
+ unlink(name);
+
+ if (posix_fallocate(fd, 0, size) != 0)
+ goto error2;
+
+ if (!(pool = wl_shm_create_pool(context->wl, fd, size)))
+ goto error2;
+
+ wl = wl_shm_pool_create_buffer(pool, 0, width, height, pitch,
+ format_wld_to_shm(format));
+ wl_shm_pool_destroy(pool);
+
+ if (!wl)
+ goto error2;
+
+ buffer_initialize(&buffer->base, &wld_buffer_impl,
+ width, height, format, pitch);
+ buffer->fd = fd;
+
+ if (!(wayland_buffer_add_exporter(&buffer->base, wl)))
+ goto error3;
+
+ return &buffer->base;
+
+ error3:
+ wl_buffer_destroy(wl);
+ error2:
+ close(fd);
+ error1:
+ free(buffer);
+ error0:
+ return NULL;
+}
+
+struct buffer * context_import_buffer(struct wld_context * context,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch)
+{
+ return NULL;
+}
+
+void context_destroy(struct wld_context * base)
+{
+ struct shm_context * context = shm_context(base);
+
+ wl_shm_destroy(context->wl);
+ wl_registry_destroy(context->registry);
+ wl_array_release(&context->formats);
+ wl_event_queue_destroy(context->base.queue);
+ free(context);
+}
+
+/**** Buffer ****/
+
+bool buffer_map(struct buffer * base)
+{
+ struct shm_buffer * buffer = shm_buffer(&base->base);
+ void * data;
+
+ data = mmap(NULL, buffer->base.base.pitch * buffer->base.base.height,
+ PROT_READ | PROT_WRITE, MAP_SHARED, buffer->fd, 0);
+
+ if (data == MAP_FAILED)
+ return false;
+
+ buffer->base.base.map = data;
+
+ return true;
+}
+
+bool buffer_unmap(struct buffer * buffer)
+{
+ if (munmap(buffer->base.map,
+ buffer->base.pitch * buffer->base.height) == -1)
+ {
+ return false;
+ }
+
+ buffer->base.map = NULL;
+
+ return true;
+}
+
+void buffer_destroy(struct buffer * base)
+{
+ struct shm_buffer * buffer = shm_buffer(&base->base);
+
+ close(buffer->fd);
+ free(buffer);
+}
+
+void registry_global(void * data, struct wl_registry * registry, uint32_t name,
+ const char * interface, uint32_t version)
+{
+ struct shm_context * context = data;
+
+ if (strcmp(interface, "wl_shm") == 0)
+ context->wl = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+}
+
+void registry_global_remove(void * data, struct wl_registry * registry,
+ uint32_t name)
+{
+}
+
+void shm_format(void * data, struct wl_shm * wl, uint32_t format)
+{
+ struct shm_context * context = data;
+ uint32_t * added_format;
+
+ if (!(added_format = wl_array_add(&context->formats, sizeof format)))
+ return;
+ *added_format = format;
+}
+
diff --git a/src/wld/wayland.c b/src/wld/wayland.c
new file mode 100644
index 0000000..40a4b34
--- /dev/null
+++ b/src/wld/wayland.c
@@ -0,0 +1,308 @@
+/* wld: wayland.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wayland.h"
+#include "wayland-private.h"
+#include "wld-private.h"
+
+#include <stdlib.h>
+#include <wayland-client.h>
+
+struct wayland_buffer
+{
+ struct wld_exporter exporter;
+ struct wld_destructor destructor;
+ struct wl_buffer * wl;
+};
+
+struct wayland_buffer_socket
+{
+ struct buffer_socket base;
+ struct wl_buffer_listener listener;
+ struct wld_surface * surface;
+ struct wl_surface * wl;
+ struct wl_display * display;
+ struct wl_event_queue * queue;
+};
+
+static bool buffer_socket_attach(struct buffer_socket * socket,
+ struct buffer * buffer);
+static void buffer_socket_process(struct buffer_socket * socket);
+static void buffer_socket_destroy(struct buffer_socket * socket);
+
+static const struct buffer_socket_impl buffer_socket_impl = {
+ .attach = &buffer_socket_attach,
+ .process = &buffer_socket_process,
+ .destroy = &buffer_socket_destroy
+};
+
+IMPL(wayland_buffer_socket, buffer_socket)
+
+static void sync_done(void * data, struct wl_callback * callback,
+ uint32_t msecs);
+
+static const struct wl_callback_listener sync_listener = {
+ .done = &sync_done
+};
+
+static void buffer_release(void * data, struct wl_buffer * buffer);
+
+const static struct wayland_impl * impls[] = {
+#if WITH_WAYLAND_DRM
+ [WLD_DRM] = &drm_wayland_impl,
+#endif
+
+#if WITH_WAYLAND_SHM
+ [WLD_SHM] = &shm_wayland_impl,
+#endif
+};
+
+enum wld_wayland_interface_id interface_id(const char * string)
+{
+ if (strcmp(string, "drm") == 0)
+ return WLD_DRM;
+ if (strcmp(string, "shm") == 0)
+ return WLD_SHM;
+
+ fprintf(stderr, "Unknown Wayland interface specified: '%s'\n", string);
+
+ return WLD_NONE;
+}
+
+EXPORT
+struct wld_context * wld_wayland_create_context
+ (struct wl_display * display, enum wld_wayland_interface_id id, ...)
+{
+ struct wayland_context * context = NULL;
+ struct wl_event_queue * queue;
+ va_list requested_impls;
+ bool impls_tried[ARRAY_LENGTH(impls)] = {0};
+ const char * interface_string;
+
+ if (!(queue = wl_display_create_queue(display)))
+ return NULL;
+
+ if ((interface_string = getenv("WLD_WAYLAND_INTERFACE")))
+ {
+ id = interface_id(interface_string);
+
+ if ((context = impls[id]->create_context(display, queue)))
+ return &context->base;
+
+ fprintf(stderr, "Could not create context for Wayland interface '%s'\n",
+ interface_string);
+
+ return NULL;
+ }
+
+ va_start(requested_impls, id);
+
+ while (id >= 0)
+ {
+ if (impls_tried[id] || !impls[id])
+ continue;
+
+ if ((context = impls[id]->create_context(display, queue)))
+ goto done;
+
+ impls_tried[id] = true;
+ id = va_arg(requested_impls, enum wld_wayland_interface_id);
+ }
+
+ va_end(requested_impls);
+
+ /* If the user specified WLD_ANY, try any remaining implementations. */
+ if (!context && id == WLD_ANY)
+ {
+ for (id = 0; id < ARRAY_LENGTH(impls); ++id)
+ {
+ if (impls_tried[id] || !impls[id])
+ continue;
+
+ if ((context = impls[id]->create_context(display, queue)))
+ break;
+ }
+ }
+
+ if (!context)
+ {
+ DEBUG("Could not initialize any of the specified implementations\n");
+ return NULL;
+ }
+
+ done:
+ context->impl = impls[id];
+ context->display = display;
+ context->queue = queue;
+
+ return &context->base;
+}
+
+EXPORT
+struct wld_surface * wld_wayland_create_surface(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags,
+ struct wl_surface * wl)
+{
+ struct wayland_buffer_socket * socket;
+
+ if (!(socket = malloc(sizeof *socket)))
+ goto error0;
+
+ socket->base.impl = &buffer_socket_impl;
+ socket->listener.release = &buffer_release;
+ socket->wl = wl;
+ socket->queue = ((struct wayland_context *) context)->queue;
+ socket->display = ((struct wayland_context *) context)->display;
+ socket->surface = buffered_surface_create(context, width, height, format,
+ flags, &socket->base);
+
+ if (!socket->surface)
+ goto error1;
+
+ return socket->surface;
+
+ error1:
+ free(socket);
+ error0:
+ return NULL;
+}
+
+EXPORT
+bool wld_wayland_has_format(struct wld_context * base, uint32_t format)
+{
+ struct wayland_context * context = (void *) base;
+
+ return context->impl->has_format(base, format);
+}
+
+static bool buffer_export(struct wld_exporter * exporter,
+ struct wld_buffer * buffer,
+ uint32_t type, union wld_object * object)
+{
+ struct wayland_buffer * wayland_buffer
+ = CONTAINER_OF(exporter, struct wayland_buffer, exporter);
+
+ switch (type)
+ {
+ case WLD_WAYLAND_OBJECT_BUFFER:
+ object->ptr = wayland_buffer->wl;
+ return true;
+ default: return false;
+ }
+}
+
+static void buffer_destroy(struct wld_destructor * destructor)
+{
+ struct wayland_buffer * wayland_buffer
+ = CONTAINER_OF(destructor, struct wayland_buffer, destructor);
+
+ wl_buffer_destroy(wayland_buffer->wl);
+ free(wayland_buffer);
+}
+
+bool wayland_buffer_add_exporter(struct buffer * buffer, struct wl_buffer * wl)
+{
+ struct wayland_buffer * wayland_buffer;
+
+ if (!(wayland_buffer = malloc(sizeof *wayland_buffer)))
+ return false;
+
+ wayland_buffer->wl = wl;
+ wayland_buffer->exporter.export = &buffer_export;
+ wld_buffer_add_exporter(&buffer->base, &wayland_buffer->exporter);
+ wayland_buffer->destructor.destroy = &buffer_destroy;
+ wld_buffer_add_destructor(&buffer->base, &wayland_buffer->destructor);
+
+ return true;
+}
+
+bool buffer_socket_attach(struct buffer_socket * base, struct buffer * buffer)
+{
+ struct wayland_buffer_socket * socket = wayland_buffer_socket(base);
+ struct wl_buffer * wl;
+ union wld_object object;
+
+ if (!wld_export(&buffer->base, WLD_WAYLAND_OBJECT_BUFFER, &object))
+ return false;
+
+ wl = object.ptr;
+
+ if (!wl_proxy_get_listener((struct wl_proxy *) wl))
+ wl_buffer_add_listener(wl, &socket->listener, buffer);
+
+ wl_surface_attach(socket->wl, wl, 0, 0);
+
+ if (pixman_region32_not_empty(&buffer->base.damage))
+ {
+ pixman_box32_t * box;
+ int num_boxes;
+
+ box = pixman_region32_rectangles(&buffer->base.damage, &num_boxes);
+
+ while (num_boxes--)
+ {
+ wl_surface_damage(socket->wl, box->x1, box->y1,
+ box->x2 - box->x1, box->y2 - box->y1);
+ }
+ }
+
+ wl_surface_commit(socket->wl);
+
+ return true;
+}
+
+void buffer_socket_process(struct buffer_socket * base)
+{
+ struct wayland_buffer_socket * socket = wayland_buffer_socket(base);
+
+ /* Since events for our wl_buffers lie in a special queue used by WLD, we
+ * must dispatch these events here so that we see any release events before
+ * the next back buffer is chosen. */
+ wl_display_dispatch_queue_pending(socket->display, socket->queue);
+}
+
+void buffer_socket_destroy(struct buffer_socket * socket)
+{
+ free(socket);
+}
+
+void sync_done(void * data, struct wl_callback * callback, uint32_t msecs)
+{
+ bool * done = data;
+
+ *done = true;
+ wl_callback_destroy(callback);
+}
+
+void buffer_release(void * data, struct wl_buffer * wl)
+{
+ struct wld_buffer * buffer = data;
+ const struct wl_buffer_listener * listener
+ = wl_proxy_get_listener((struct wl_proxy *) wl);
+ struct wayland_buffer_socket * socket
+ = CONTAINER_OF(listener, struct wayland_buffer_socket, listener);
+
+ wld_surface_release(socket->surface, buffer);
+}
+
diff --git a/src/wld/wayland.h b/src/wld/wayland.h
new file mode 100644
index 0000000..3127ee6
--- /dev/null
+++ b/src/wld/wayland.h
@@ -0,0 +1,84 @@
+/* wld: wayland.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_WAYLAND_H
+#define WLD_WAYLAND_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct wl_display;
+struct wl_surface;
+
+#define WLD_WAYLAND_ID (0x3 << 24)
+
+enum wld_wayland_interface_id
+{
+ /**
+ * Give up on trying any new interfaces. This can be considered as a
+ * sentinel for wld_wayland_create_context.
+ */
+ WLD_NONE = -2,
+
+ /**
+ * Try any available interface.
+ */
+ WLD_ANY = -1,
+ WLD_DRM,
+ WLD_SHM
+};
+
+enum wld_wayland_object_type
+{
+ WLD_WAYLAND_OBJECT_BUFFER = WLD_WAYLAND_ID
+};
+
+/**
+ * Create a new WLD context which uses various available Wayland interfaces
+ * (such as wl_shm and wl_drm) to create wl_buffers backed by implementations
+ * specific to the interface.
+ *
+ * You can specify the particular interface you want to use by specifying them
+ * as arguments. Interfaces will be tried in the order they are given.
+ *
+ * The last argument must be either WLD_NONE or WLD_ANY.
+ *
+ * @see enum wld_wayland_interface_id
+ */
+struct wld_context * wld_wayland_create_context
+ (struct wl_display * display, enum wld_wayland_interface_id id, ...);
+
+struct wld_surface * wld_wayland_create_surface(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags,
+ struct wl_surface * surface);
+
+/**
+ * Check if the wayland implementation supports a particular pixel format.
+ *
+ * @see enum wld_format
+ */
+bool wld_wayland_has_format(struct wld_context * context, uint32_t format);
+
+#endif
+
diff --git a/src/wld/wld-private.h b/src/wld/wld-private.h
new file mode 100644
index 0000000..e812b11
--- /dev/null
+++ b/src/wld/wld-private.h
@@ -0,0 +1,243 @@
+/* wld: wld-private.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_PRIVATE_H
+#define WLD_PRIVATE_H
+
+#include "wld.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BITMAP_H
+
+#define ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0])
+#if ENABLE_DEBUG
+# define DEBUG(format, ...) \
+ fprintf(stderr, "# %s: " format, __func__, ## __VA_ARGS__)
+#else
+# define DEBUG(format, ...)
+#endif
+
+#define EXPORT __attribute__((visibility("default")))
+#define CONTAINER_OF(ptr, type, member) \
+ ((type *)((uintptr_t) ptr - offsetof(type, member)))
+#define IMPL(impl_type, base_type) \
+ static inline struct impl_type * impl_type(struct base_type * object) \
+ { \
+ assert(object->impl == &base_type ## _impl); \
+ return (struct impl_type *) object; \
+ }
+
+struct wld_font_context
+{
+ FT_Library library;
+};
+
+struct glyph
+{
+ FT_Bitmap bitmap;
+
+ /**
+ * The offset from the origin to the top left corner of the bitmap.
+ */
+ int16_t x, y;
+
+ /**
+ * The width to advance to the origin of the next character.
+ */
+ uint16_t advance;
+};
+
+struct font
+{
+ struct wld_font base;
+
+ struct wld_font_context * context;
+ FT_Face face;
+ struct glyph ** glyphs;
+};
+
+struct wld_context_impl
+{
+ struct wld_renderer * (* create_renderer)(struct wld_context * context);
+ struct buffer * (* create_buffer)(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags);
+ struct buffer * (* import_buffer)(struct wld_context * context,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch);
+ struct wld_surface * (* create_surface)(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags);
+ void (* destroy)(struct wld_context * context);
+};
+
+struct wld_renderer_impl
+{
+ uint32_t (* capabilities)(struct wld_renderer * renderer,
+ struct buffer * buffer);
+ bool (* set_target)(struct wld_renderer * renderer, struct buffer * buffer);
+ void (* fill_rectangle)(struct wld_renderer * renderer,
+ uint32_t color, int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+ void (* fill_region)(struct wld_renderer * renderer,
+ uint32_t color, pixman_region32_t * region);
+ void (* copy_rectangle)(struct wld_renderer * renderer, struct buffer * src,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height);
+ void (* copy_region)(struct wld_renderer * renderer, struct buffer * src,
+ int32_t dst_x, int32_t dst_y,
+ pixman_region32_t * region);
+ void (* draw_text)(struct wld_renderer * renderer,
+ struct font * font, uint32_t color,
+ int32_t x, int32_t y, const char * text, uint32_t length,
+ struct wld_extents * extents);
+ void (* flush)(struct wld_renderer * renderer);
+ void (* destroy)(struct wld_renderer * renderer);
+};
+
+struct buffer
+{
+ struct wld_buffer base;
+
+ unsigned references, map_references;
+ struct wld_exporter * exporters;
+ struct wld_destructor * destructors;
+};
+
+struct wld_buffer_impl
+{
+ bool (* map)(struct buffer * buffer);
+ bool (* unmap)(struct buffer * buffer);
+ void (* destroy)(struct buffer * buffer);
+};
+
+struct wld_surface_impl
+{
+ pixman_region32_t * (* damage)(struct wld_surface * surface,
+ pixman_region32_t * damage);
+ struct buffer * (* back)(struct wld_surface * surface);
+ struct buffer * (* take)(struct wld_surface * surface);
+ bool (* release)(struct wld_surface * surface, struct buffer * buffer);
+ bool (* swap)(struct wld_surface * surface);
+ void (* destroy)(struct wld_surface * surface);
+};
+
+struct buffer_socket
+{
+ const struct buffer_socket_impl * impl;
+};
+
+struct buffer_socket_impl
+{
+ bool (* attach)(struct buffer_socket * socket, struct buffer * buffer);
+ void (* process)(struct buffer_socket * socket);
+ void (* destroy)(struct buffer_socket * socket);
+};
+
+bool font_ensure_glyph(struct font * font, FT_UInt glyph_index);
+
+/**
+ * Returns the number of bytes per pixel for the given format.
+ */
+static inline uint8_t format_bytes_per_pixel(enum wld_format format)
+{
+ switch (format)
+ {
+ case WLD_FORMAT_ARGB8888:
+ case WLD_FORMAT_XRGB8888:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+static inline pixman_format_code_t format_wld_to_pixman(uint32_t format)
+{
+ switch (format)
+ {
+ case WLD_FORMAT_ARGB8888:
+ return PIXMAN_a8r8g8b8;
+ case WLD_FORMAT_XRGB8888:
+ return PIXMAN_x8r8g8b8;
+ default:
+ return 0;
+ }
+}
+
+static inline uint32_t format_pixman_to_wld(pixman_format_code_t format)
+{
+ switch (format)
+ {
+ case PIXMAN_a8r8g8b8:
+ return WLD_FORMAT_ARGB8888;
+ case PIXMAN_x8r8g8b8:
+ return WLD_FORMAT_XRGB8888;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * This default fill_region method is implemented in terms of fill_rectangle.
+ */
+void default_fill_region(struct wld_renderer * renderer, uint32_t color,
+ pixman_region32_t * region);
+
+/**
+ * This default copy_region method is implemented in terms of copy_rectangle.
+ */
+void default_copy_region(struct wld_renderer * renderer, struct buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ pixman_region32_t * region);
+
+struct wld_surface * default_create_surface(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags);
+
+struct wld_surface * buffered_surface_create(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags,
+ struct buffer_socket * socket);
+
+void context_initialize(struct wld_context * context,
+ const struct wld_context_impl * impl);
+
+void renderer_initialize(struct wld_renderer * renderer,
+ const struct wld_renderer_impl * impl);
+
+void buffer_initialize(struct buffer * buffer,
+ const struct wld_buffer_impl * impl,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch);
+
+void surface_initialize(struct wld_surface * surface,
+ const struct wld_surface_impl * impl);
+
+#endif
+
diff --git a/src/wld/wld.h b/src/wld/wld.h
new file mode 100644
index 0000000..c36081c
--- /dev/null
+++ b/src/wld/wld.h
@@ -0,0 +1,283 @@
+/* wld: wld.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WLD_H
+#define WLD_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <pixman.h>
+#include <fontconfig/fontconfig.h>
+
+#define WLD_USER_ID (0xff << 24)
+
+#define __WLD_FOURCC(a, b, c, d) ( (a) \
+ | ((b) << 8) \
+ | ((c) << 16) \
+ | ((d) << 24) )
+
+/**
+ * Supported pixel formats.
+ *
+ * These formats can safely be interchanged with GBM and wl_drm formats.
+ */
+enum wld_format
+{
+ WLD_FORMAT_XRGB8888 = __WLD_FOURCC('X', 'R', '2', '4'),
+ WLD_FORMAT_ARGB8888 = __WLD_FOURCC('A', 'R', '2', '4')
+};
+
+enum wld_flags
+{
+ WLD_FLAG_MAP = 0x1 << 16
+};
+
+bool wld_lookup_named_color(const char * name, uint32_t * color);
+
+/**** WLD Context ****/
+
+enum wld_object_type
+{
+ WLD_OBJECT_DATA
+};
+
+union wld_object
+{
+ void * ptr;
+ uint32_t u32;
+ int i;
+};
+
+struct wld_context
+{
+ const struct wld_context_impl * const impl;
+};
+
+struct wld_renderer * wld_create_renderer(struct wld_context * context);
+
+struct wld_buffer * wld_create_buffer(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags);
+
+struct wld_buffer * wld_import_buffer(struct wld_context * context,
+ uint32_t type, union wld_object object,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t pitch);
+
+struct wld_surface * wld_create_surface(struct wld_context * context,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags);
+
+void wld_destroy_context(struct wld_context * context);
+
+/**** Font Handling ****/
+
+struct wld_extents
+{
+ uint32_t advance;
+};
+
+struct wld_font
+{
+ uint32_t ascent, descent;
+ uint32_t height;
+ uint32_t max_advance;
+};
+
+/**
+ * Create a new font context.
+ *
+ * This sets up the underlying FreeType library.
+ */
+struct wld_font_context * wld_font_create_context();
+
+/**
+ * Destroy a font context.
+ */
+void wld_font_destroy_context(struct wld_font_context * context);
+
+/**
+ * Open a new font from the given fontconfig match.
+ */
+struct wld_font * wld_font_open_pattern(struct wld_font_context * context,
+ FcPattern * match);
+
+/**
+ * Open a new font from a fontconfig pattern string.
+ */
+struct wld_font * wld_font_open_name(struct wld_font_context * context,
+ const char * name);
+
+/**
+ * Close a font.
+ */
+void wld_font_close(struct wld_font * font);
+
+/**
+ * Check if the given font has a particular character (in UTF-32), and if so,
+ * load the glyph.
+ */
+bool wld_font_ensure_char(struct wld_font * font, uint32_t character);
+
+/**
+ * Calculate the text extents of the given UTF-8 string.
+ *
+ * @param length The maximum number of bytes in the string to process
+ */
+void wld_font_text_extents_n(struct wld_font * font,
+ const char * text, int32_t length,
+ struct wld_extents * extents);
+
+static inline void wld_font_text_extents(struct wld_font * font,
+ const char * text,
+ struct wld_extents * extents)
+{
+ wld_font_text_extents_n(font, text, INT32_MAX, extents);
+}
+
+/**** Buffers ****/
+
+struct wld_exporter
+{
+ bool (* export)(struct wld_exporter * exporter, struct wld_buffer * buffer,
+ uint32_t type, union wld_object * object);
+ struct wld_exporter * next;
+};
+
+struct wld_destructor
+{
+ void (* destroy)(struct wld_destructor * destructor);
+ struct wld_destructor * next;
+};
+
+struct wld_buffer
+{
+ const struct wld_buffer_impl * const impl;
+
+ uint32_t width, height, pitch;
+ enum wld_format format;
+ pixman_region32_t damage;
+ void * map;
+};
+
+bool wld_map(struct wld_buffer * buffer);
+bool wld_unmap(struct wld_buffer * buffer);
+
+bool wld_export(struct wld_buffer * buffer,
+ uint32_t type, union wld_object * object);
+
+void wld_buffer_add_exporter(struct wld_buffer * buffer,
+ struct wld_exporter * exporter);
+
+void wld_buffer_add_destructor(struct wld_buffer * buffer,
+ struct wld_destructor * destructor);
+
+/**
+ * Increase the reference count of a buffer.
+ */
+void wld_buffer_reference(struct wld_buffer * buffer);
+
+/**
+ * Decrease the reference count of a buffer.
+ *
+ * When the reference count drops to zero, the buffer will be destroyed.
+ */
+void wld_buffer_unreference(struct wld_buffer * buffer);
+
+/**** Surfaces ****/
+
+struct wld_surface
+{
+ const struct wld_surface_impl * const impl;
+};
+
+pixman_region32_t * wld_surface_damage(struct wld_surface * surface,
+ pixman_region32_t * new_damage);
+
+struct wld_buffer * wld_surface_take(struct wld_surface * surface);
+
+void wld_surface_release(struct wld_surface * surface,
+ struct wld_buffer * buffer);
+
+bool wld_swap(struct wld_surface * surface);
+
+void wld_destroy_surface(struct wld_surface * surface);
+
+/**** Renderers ****/
+
+struct wld_renderer
+{
+ const struct wld_renderer_impl * const impl;
+ struct wld_buffer * target;
+};
+
+enum wld_capability
+{
+ WLD_CAPABILITY_READ = 1<<0,
+ WLD_CAPABILITY_WRITE = 1<<1,
+};
+
+void wld_destroy_renderer(struct wld_renderer * renderer);
+
+uint32_t wld_capabilities(struct wld_renderer * renderer,
+ struct wld_buffer * buffer);
+
+bool wld_set_target_buffer(struct wld_renderer * renderer,
+ struct wld_buffer * buffer);
+
+bool wld_set_target_surface(struct wld_renderer * renderer,
+ struct wld_surface * surface);
+
+void wld_fill_rectangle(struct wld_renderer * renderer, uint32_t color,
+ int32_t x, int32_t y, uint32_t width, uint32_t height);
+
+void wld_fill_region(struct wld_renderer * renderer, uint32_t color,
+ pixman_region32_t * region);
+
+void wld_copy_rectangle(struct wld_renderer * renderer,
+ struct wld_buffer * buffer,
+ int32_t dst_x, int32_t dst_y,
+ int32_t src_x, int32_t src_y,
+ uint32_t width, uint32_t height);
+
+void wld_copy_region(struct wld_renderer * renderer,
+ struct wld_buffer * buffer,
+ int32_t dst_x, int32_t dst_y, pixman_region32_t * region);
+
+/**
+ * Draw a UTF-8 text string to the given buffer.
+ *
+ * @param length The maximum number of bytes in the string to process. If
+ * length is -1, then draw until a NULL byte is found.
+ * @param extents If not NULL, will be initialized to the extents of the
+ * drawn text
+ */
+void wld_draw_text(struct wld_renderer * renderer,
+ struct wld_font * font, uint32_t color,
+ int32_t x, int32_t y, const char * text, uint32_t length,
+ struct wld_extents * extents);
+
+void wld_flush(struct wld_renderer * renderer);
+
+#endif
+
diff --git a/src/wld/wld.pc.in b/src/wld/wld.pc.in
new file mode 100644
index 0000000..e9790a1
--- /dev/null
+++ b/src/wld/wld.pc.in
@@ -0,0 +1,13 @@
+prefix=@PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: wld
+Description: A primitive drawing library library targeted at Wayland
+Version: @VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwld
+
+Requires: @WLD_REQUIRES@
+Requires.private: @WLD_REQUIRES_PRIVATE@
+