/dev/dinxwin
and /dev/dinxsvr
character device nodes, as well as a /proc/dinx
entry for
monitoring status. It also exports functions to register and
unregister blitter modules.
dinx_fill_rect()
writes a command to fill a
rectangular area of a window to a /dev/dinxwin
node.
/dev/dinxsvr
. It
handles framebuffer selection, virtual console switching, mouse and
keyboard events, as well as requests from client window programs to
create and reposition windows.
/dev/dinxwin
nodes and write commands to
perform drawing and send messages to the server. They read back reply
messages from the server, as well as user events and notifications that
some part of a window requires redrawing.
At any given moment, a window may be mapped or unmapped. A new window is unmapped when created, which means that it holds a position in the stacking order but is not visible, does not participate in clipping, and cannot be drawn to. Only the window server may map and unmap windows, usually at the request of the client program via a message. The same goes for setting the size and position of a window.
int
values. Vectors and rectangles are
defined as follows:
#include <linux/dinx.h> typedef struct dvect { int x, y; } dvect; typedef struct drect { int x1, y1; int x2, y2; } drect; |
It is important to note that coordinates are not pixel numbers, rather they are offsets to the dividing lines between pixels. The diagram above shows the rectangle (x1 = 3, y1 = 2), (x2 = 9, y2 = 6). So when a rectangle is drawn to a buffer, it includes the pixels [x1 <= x < x2), [y1 <= y < y2).
Each window has a bounds rectangle and an origin vector. The window origin is relative to the origin of the display (top-left corner) and the bounds is relative to the origin. So a window whose origin is at the top-left of the window would have a bounds rectangle with (x1 = 0, y1 = 0), (x2 = width, y2 = height).
Vectors and rectangles that are relative to the origin of the display are said to be in the global coordinate space. Coordinates that are relative to the window origin are said to be in the window coordinate space.
unsigned long
values to identify
client windows when communicating with the server. These values are
actually pointers to kernel data structures, but they are checked for
validity before being dereferenced. A window identifier has the same
lifetime as the window itself.
unsigned long
words. Where more than one display pixel value
will fit in a word, the pixel value is repeated throughout the word in the
same packing as the display. This relieves the blitter from shifting a
pixel value when performing word-wide accesses.
The windowing module does not deal with configuring display palettes. This is left to the server program, which should operate directly on the framebuffer device. Client window programs should communicate with the server to request palette entries, pixel format information etc.
Despite the fact that DinX only deals directly with lists of top-level
windows, each such list is referred to here as a window tree. Each tree is
managed by a server process attached to the /dev/dinxsvr
node
for that tree. Currently the number of window trees is limited to sixteen.
Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Meaning: |
The `Server' flag is zero for dinxwin
window nodes, and one for
dinxsvr
server nodes. For each of the sixteen trees (specified
by the lower four bits) there should be a window node and a tree node. A
typical set of device nodes might look like this:
lrwxrwxrwx 1 root root 8 /dev/dinxwin -> dinxwin0 crw-rw-rw- 1 root root 60, 0 /dev/dinxwin0 crw-rw-rw- 1 root root 60, 1 /dev/dinxwin1 crw-rw-rw- 1 root root 60, 2 /dev/dinxwin2 crw-rw-rw- 1 root root 60, 3 /dev/dinxwin3 crw-rw-rw- 1 root root 60, 4 /dev/dinxwin4 crw-rw-rw- 1 root root 60, 5 /dev/dinxwin5 crw-rw-rw- 1 root root 60, 6 /dev/dinxwin6 crw-rw-rw- 1 root root 60, 7 /dev/dinxwin7 crw-rw-rw- 1 root root 60, 8 /dev/dinxwin8 crw-rw-rw- 1 root root 60, 9 /dev/dinxwin9 crw-rw-rw- 1 root root 60, 10 /dev/dinxwin10 crw-rw-rw- 1 root root 60, 11 /dev/dinxwin11 crw-rw-rw- 1 root root 60, 12 /dev/dinxwin12 crw-rw-rw- 1 root root 60, 13 /dev/dinxwin13 crw-rw-rw- 1 root root 60, 14 /dev/dinxwin14 crw-rw-rw- 1 root root 60, 15 /dev/dinxwin15 lrwxrwxrwx 1 root root 8 /dev/dinxsvr -> dinxsvr0 crw------- 1 root root 60, 128 /dev/dinxsvr0 crw------- 1 root root 60, 129 /dev/dinxsvr1 crw------- 1 root root 60, 130 /dev/dinxsvr2 crw------- 1 root root 60, 131 /dev/dinxsvr3 crw------- 1 root root 60, 132 /dev/dinxsvr4 crw------- 1 root root 60, 133 /dev/dinxsvr5 crw------- 1 root root 60, 134 /dev/dinxsvr6 crw------- 1 root root 60, 135 /dev/dinxsvr7 crw------- 1 root root 60, 136 /dev/dinxsvr8 crw------- 1 root root 60, 137 /dev/dinxsvr9 crw------- 1 root root 60, 138 /dev/dinxsvr10 crw------- 1 root root 60, 139 /dev/dinxsvr11 crw------- 1 root root 60, 140 /dev/dinxsvr12 crw------- 1 root root 60, 141 /dev/dinxsvr13 crw------- 1 root root 60, 142 /dev/dinxsvr14 crw------- 1 root root 60, 143 /dev/dinxsvr15
dinxwin
nodes dinxwin
node may be opened many times by the same client
process and by seperate processes. Each new file stream creates a new
window in the tree specified by the minor number of the node opened. The
newly created window is unmapped and has zero size. The window will
continue to exist until the file stream is closed. Opening may fail with
one of the following error numbers:
ENOMEM | The module was unable to allocate internal data structures. |
EPIPE | There is no server attached to the corresponding dinxsvr node. |
dinxsvr
nodes dinxsvr
node may be opened only once at a time. While a
server is attached, the corresponding window tree is available for client
programs. When the server detaches by closing the file stream, any
remaining client programs still attached to the tree will receive a
SIGPIPE
signal when next they attempt to read or write events
or commands. A new server may not attach to the tree until all the client
programs have detached. Opening the dinxsvr
node may fail with
the following error number:
EBUSY | The tree already has a server attached, or is waiting for remaining clients to detach after the previous server closed. |
union dcommand
defined in
<linux/dinx.h>
. Every write()
operation
must pass a buffer that is at least sizeof(union dcommand)
bytes in size.
Some command structures contain pointers into user-space memory. Depending
on the command, the memory pointed to may be read by the module (in which
case the pointer will have a const
qualifer) or it may be
written back. The latter case is equivalent to calling a function with a
pointer to an area where it may write results for return to the caller.
Passing variable-length data by reference in this way keeps the device protocol simple, because it always deals with fixed-size quantities. It is also efficient, because it eliminates an unneccessary copy of the data into kernel buffer memory before it is operated on. For example, blitting operations that copy raw pixmap data to a window can copy directly from the client's buffer to the framebuffer.
The return value from the write()
operation is the number of
bytes successfully written, or -1 and an error code in errno
,
as one would expect. The module will return errors that arise while
performing a command; for example if the client writes a fill_rect
command with an invalid pointer to the pixmap source buffer, an
EFAULT
error will result. If the failing command was preceeded
by one or more successful commands in the same write()
operation, the successful byte count will be returned. Then when the
program retries the failing command, the error code will be returned. This
prevents repeating the successful commands, and allows the offending
command to be located in the command stream.
The first element of any command is an enumerated type
value
that specifies the command. Command names are of the form
DCOMMAND_FILL_RECT
, for example. The format of the rest of the
buffer must correspond to the appropriate structure for that command, e.g.
struct dcommand_fill_rect
.
Errors that may be encountered when writing commands:
EINVAL | The size of the buffer written is smaller than a complete command, the type of the command is invalid, or some other paramater in the command structure is invalid. |
EFAULT | The command structure contains a pointer to a buffer that is outside the accessible address space. |
ENOSYS | The command specifies a blitting operation that is not implemented by the current blitter. (Not all blitters implement all copy operations, see the next chapter for details.) |
EPIPE | The server for this window tree has detached. |
ENOMEM | The command was unable to allocate memory, e.g. to add an event to a queue. |
union devent
. Every
read()
operation must provide a buffer that is at least
sizeof(union devent)
bytes in size.
The first element of every event structure is an enumerated
type
value that specifies the event. Event names are of the
form DEVENT_REDRAW
, for example. The format of the rest of the
buffer corresponds to the appropriate structure for the event, e.g.
struct devent_redraw
.
Both blocking and non-blocking reading is supported. A read()
operation will block until a complete event is ready, unless
O_NONBLOCK
is specified for the file stream. The
poll()
, and therefore select()
, operations are
also supported.
Errors that may be encountered when reading events:
EINVAL | The size of the buffer provided is smaller than a complete event. |
EAGAIN | No event is waiting to be read, and O_NONBLOCK was
specified. |
EINTR | A signal occured while waiting for an event. |
union dcommand { enum dcommand_type type; struct dcommand_message message; struct dcommand_fill_rect fill_rect; struct dcommand_move_rect move_rect; struct dcommand_copy_rect copy_rect; ... };
For example, to send a DCOMMAND_FILL_RECT command:
union dcommand command; command.type = DCOMMAND_FILL_RECT; command.fill_rect.rect = some_rectangle; command.fill_rect.col = some_colour; write(window_fd, &command, sizeof(union dcommand));
struct dcommand_message { enum dcommand_type type; /* DCOMMAND_MESSAGE */ unsigned long win; char data[DINX_MESSAGE_SIZE]; };
win | Ignored in the case of messages sent by windows. |
data | Contents of the message. The format of this block is defined by the
server. Refer to the chapter on the server program, and <dinx/messages.h> . |
struct dcommand_fill_rect { enum dcommand_type type; /* DCOMMAND_FILL_RECT */ drect rect; unsigned long col; };
rect | The rectangle to be filled, in window coordinates. |
col | The colour with which to fill, as a pixel value. |
struct dcommand_move_rect { enum dcommand_type type; /* DCOMMAND_MOVE_RECT */ drect rect; dvect moveby; };
rect | The destination rectangle, in window coordinates. |
moveby | The vector offset, which points from the source rectangle to the destination rectangle. The source rectangle is implied by rect and moveby. |
This command generates redraw events for the portions of the destination rectangle for which the source rectangle is not visible, as shown in the diagram above.
struct dcommand_copy_rect { enum dcommand_type type; /* DCOMMAND_COPY_RECT */ drect dest; dvect base; const void * src; int src_width; int src_bpp; const unsigned long * pal; };
dest | The destination rectangle, in window coordinates. |
base | Point in the window that corresponds to the top-left of the entire pixmap, i.e. src. May be outside the window. |
src | Pointer to the start of source pixmap data. |
src_width | Bytes per line in the source pixmap data. This implies that each line of pixmap data must begin on a byte boundary. |
src_bpp | Depth (bits per pixel) of the source pixmap. Not all blitters will copy from all source depths, see the next chapter on blitters. |
pal | Pointer to an array of palette entries, or NULL if no palette conversion is required. The palette contains one unsigned long display pixel value for each possible source pixel value, so the size of the palette is determined by src_bpp. |
The diagram above shows a portion of a source image (Tux's head) being copied to a window. The base vector positions the whole image, while the dest rectangle specifies which part of it is to be copied.
union dcommand { enum dcommand_type type; struct dcommand_message message; ... struct dcommand_get_status get_status; struct dcommand_set_bounds set_bounds; struct dcommand_window window; struct dcommand_select_fb select_fb; ... };
struct dcommand_message { enum dcommand_type type; /* DCOMMAND_MESSAGE */ unsigned long win; char data[DINX_MESSAGE_SIZE]; };
win | Identifies the window to send the message to. |
data | Contents of the message. The format of this block is defined by the
server. Refer to the chapter on the server program, and <dinx/messages.h> . |
struct dcommand_get_status { enum dcommand_type type; /* DCOMMAND_GET_STATUS */ unsigned long win; struct dwindow_status * status; };
win | Identifies the window to get. |
status | Pointer to a buffer where the status information will be written. |
The returned structure is defined as follows:
struct dwindow_status { unsigned long nextabove; unsigned long nextbelow; drect bounds; dvect origin; int flags; int event_count; };
nextabove | Identifies the window immediately above in the stacking order, or 0 if none. |
nextbelow | Identifies the window immediately below in the stacking order, or 0 if none. |
bounds | Current bounds rectangle, in window coordinates. |
origin | Current origin vector, in global coordinates. |
flags | Current flags; DINX_MAPPED indicates window is mapped. |
event_count | Number of events waiting in event queue. |
struct dcommand_set_bounds { enum dcommand_type type; /* DCOMMAND_SET_BOUNDS */ unsigned long win; drect bounds; dvect origin; };
win | Identifies the window to set. |
bounds | New bounds rectangle, relative to the new origin. |
origin | New origin vector, in global coordinates. |
struct dcommand_window { enum dcommand_type type; /* DCOMMAND_MAP/UNMAP/RAISE/LOWER/ PREFER_MOVE/PREFER_REDRAW */ unsigned long win; };
win | Identifies the window to manipulate. |
The move vs. redraw preference affects how the window's contents is updated when it is repositioned with set_bounds. The default is to use move_rect to move the window to the new position. This can be very slow on video hardware that is slow to read from, e.g. PC systems. In these cases, the redraw preference results in redraw events being generated for all visible parts of the window when it is moved. This preference can be set on a per-window basis, as the cost of a redraw depends on the complexity of the window's contents.
struct dcommand_select_fb { enum dcommand_type type; /* DCOMMAND_SELECT_FB */ int framebuffer; };
framebuffer | The framebuffer number to attach to. Not to be confused with the virtual console number, which is handled in the server. |
union devent { enum devent_type type; struct devent_message message; struct devent_redraw redraw; ... };
To receive and dispatch an event, you might use code like this:
union devent event; read(window_fd, &event, sizeof(union devent)); switch (event.type) { case DEVENT_REDRAW: .... }
struct devent_message { enum devent_type type; /* DEVENT_MESSAGE */ unsigned long win; char data[DINX_MESSAGE_SIZE]; };
win | Undefined in the case of messages sent to windows. |
data | Contents of the message. The format of this block is defined by the
server. Refer to the chapter on the server program, and <dinx/messages.h> . |
When a non-rectangular area of the window needs to be redrawn, a number of redraw events are generated - one for each rectangular portion of the dirty area.
struct devent_redraw { enum devent_type type; /* DEVENT_REDRAW */ drect rect; int more; };
rect | The rectangle that needs redrawing, in window coordinates. |
more | If non-zero, this indicates that the next event in the queue is also a redraw event. |
There are two strategies for dealing with redraws. The obvious and usually most appropriate is just to redraw each rectangle as events come in. The more flag allows another strategy, useful when it is inefficient to redraw many small parts of the window. The client program can choose to ignore redraw events that are followed by more redraw events, and then when the last redraw is received (i.e. more is false) to redraw the whole window. A more complicated option is to accumulate a dirty region as the events arrive, and then to redraw it all at once.
union devent { enum devent_type type; struct devent_message message; ... struct devent_win_status win_status; ... };
struct devent_message { enum devent_type type; /* DEVENT_MESSAGE */ unsigned long win; char data[DINX_MESSAGE_SIZE]; };
win | Identifies the window that sent the message. |
data | Contents of the message. The format of this block is defined by the
server. Refer to the chapter on the server program, and <dinx/messages.h> . |
struct devent_win_status { enum devent_type type; /* DEVENT_WIN_OPENED / _CLOSED / _EMPTY */ unsigned long win; };
win | Identifies the window that opened, closed or emptied. |
All blitters provide fill_rect
and move_rect
operations. In the following sections we describe which
copy_rect
operations are available, and the API that blitter
modules must conform to.
copy_rect
operations that copy from a
source buffer to a framebuffer that is of the same or greater bit depth.
Blitters will not copy from a source buffer that is deeper than the
framebuffer.
DinX is designed so that blitters for small systems with shallow bit-depth (e.g. 4bpp) buffers are the smallest and simplest, while blitters for deeper buffers (e.g. 24bpp) contain routines to handle source data of most bit-depths. This reduces code size on small systems. It also simplifies the API, because blitting from a deep source pixmap to a shallow display buffer can require extra palette information from the server. If a client program needs to draw to a 4bpp display from a 24bpp source buffer (for example) it should perform the conversion in user space (perhaps dithering in the process) and then copy the converted buffer raw to the display.
The following tables show which operations are made available by each of the blitters, and describe how each operation works.
Source | ||||||||
---|---|---|---|---|---|---|---|---|
Destination | 1bpp | 2bpp | 4bpp | 8bpp | 16bpp | 24bpp | 32bpp | |
dinx-l1.o: | pal/raw | - | - | - | - | - | - | |
dinx-l2.o: | pal | pal/raw | - | - | - | - | - | |
dinx-l4.o: | pal | pal | pal/raw | - | - | - | - | |
dinx-l8.o: | pal | pal | pal | pal/raw | - | - | - | |
dinx-l16.o: | pal | pal | pal | pal | raw | - | - | |
dinx-l24.o: | pal | pal | pal | pal | cube | raw | - | |
dinx-l32.o: | pal | pal | pal | pal | cube | pad | raw |
pal | Each pixel of the source is an index into the required palette. |
pal/raw | The palette is optional - if NULL, the data is copied raw. |
raw | The palette is ignored, the data is copied without conversion. |
cube | The 16bpp source data is treated as 5-6-5 RGB colour-cube data, and is expanded into the 8-8-8 RGB 24bpp or 32bpp destination. |
pad | The 24bpp source data is padded to the 32-bit aligned destination. |
init_module()
routine should register the blitter with the
windowing module, by calling register_blitter()
. When it is
removed from the kernel, it should unregister by calling
unregister_blitter()
. These functions are exported by the
windowing module, and are declared as follows.
extern int register_blitter(struct dinx_blitter *blitter); extern int unregister_blitter(struct dinx_blitter *blitter);
The struct blitter
structure contains the name of the blitter
to appear in /proc/dinx
, and pointers to the blitter functions,
defined as follows.
struct dinx_blitter { struct dinx_blitter *next; const char *name; int (*can_handle)(struct display *); void (*open)(void); void (*close)(void); void (*fill_rect)(struct display *, const drect *, unsigned long); void (*move_rect)(struct display *, const drect *, dvect); int (*copy_raw)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); int (*copy_1bpp)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); int (*copy_2bpp)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); int (*copy_4bpp)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); int (*copy_8bpp)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); int (*copy_16bpp)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); int (*copy_24bpp)(struct display *, const drect *, const dvect *, const void *, int, const unsigned long *); };
next | For use by the windowing module, should be NULL. |
name | Points to a string that is the name of the blitter,
as it is to appear in /proc/dinx . |
can_handle | Return non-zero if this blitter can handle the framebuffer. |
open | Called when a server selects this framebuffer, the blitter module should increment its usage count here. |
close | Called when a server selects some other framebuffer, the blitter module should decrement its usage count here. |
fill_rect | Fill a rectangle of the display with a solid colour. The rectangle passed has already been clipped to within the display. |
move_rect | Move a rectangular area of the display by a vector offset. The rectangle passed is the destination area. The vector is the offset from the source rectangle to the destination. Both the source and offset are already clipped within the display. |
copy_* | Copy a pixmap from user space to the display. The source data area has
already been checked with access_ok() . The palette (if
any) has already been copied to kernel memory. Parameters have the
same meanings as described for DCOMMAND_COPY_RECT, above. Return 0 on
success, or -EFAULT, -ENOSYS etc. |
copy_raw | The source is the same depth (bpp) as the display, and no palette transformation is to be applied. Ignore palette. |
copy_1bpp | The source is 1bpp, the palette contains 2 entries. |
copy_2bpp | The source is 2bpp, the palette contains 4 entries. |
copy_4bpp | The source is 4bpp, the palette contains 16 entries. |
copy_8bpp | The source is 8bpp, the palette contains 256 entries. |
copy_16bpp | The source is 16bpp 5-6-5 RGB, expand into 8-8-8 RGB for 24bpp or 32bpp displays. Ignore palette. |
copy_24bpp | The source is 24bpp 8-8-8 RGB, pad for 32bpp 8-8-8-x RGBx displays. Ignore palette. |
Copyright © 1999 Ben Williamson