diff options
Diffstat (limited to 'src')
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, ®listener, 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 = ®istry_global, + .global_remove = ®istry_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, ®istry_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 = ®istry_global, + .global_remove = ®istry_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, ®istry_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@ + |