mirror of
https://github.com/ctm/executor.git
synced 2024-11-23 20:32:28 +00:00
282 lines
14 KiB
Plaintext
282 lines
14 KiB
Plaintext
|
Each host is required to provide a "vdriver" package that presents a
|
||
|
consistent video interface to the rest of Executor.
|
||
|
|
||
|
The vdriver provides an idealized rectangular frame buffer to
|
||
|
Executor. Pixels occupy either 1, 2, 4, or 8 bits and are stored in
|
||
|
in "packed" format in big endian bit order (MSB on the left). The
|
||
|
frame buffer bytes per row may exceed the bytes occupied by the pixels
|
||
|
on that row, but both sizes will always be multiples of four bytes.
|
||
|
|
||
|
The actual video hardware on the host machine will constrain the
|
||
|
maximum pixel depths and screen sizes available to Executor, but the
|
||
|
hardware modes used need not map directly to the format of the
|
||
|
vdriver's frame buffer. The vdriver is responsible for selecting
|
||
|
efficient hardware graphics modes and translating the information in
|
||
|
the internal frame buffer into bits that appear on the real screen
|
||
|
when `vdriver_update_screen' is called. The "internal" frame buffer
|
||
|
may optionally be one and the same as the actual hardware frame
|
||
|
buffer, in which case `vdriver_update_screen' does nothing.
|
||
|
|
||
|
For example, consider the case where Executor requests a 4 bpp (bits
|
||
|
per pixel) frame buffer on a SuperVGA system. On most SuperVGA
|
||
|
boards, 4 bpp requires using a complicated and slow "planar mode".
|
||
|
Therefore, the vdriver might choose to use an available SuperVGA 8 bpp
|
||
|
mode and use lookup tables to convert from 4 bpp to 8 bpp whenever the
|
||
|
hardware screen is updated, since this is faster than converting from
|
||
|
4 bpp "packed" pixels to 4 bpp "planar" pixels. Executor will still
|
||
|
only "see" a 4 bpp frame buffer, and the user won't be able to tell
|
||
|
the difference.
|
||
|
|
||
|
Each vdriver maintains a maximum bits per pixel and a list of
|
||
|
acceptable screen sizes. The vdriver must be able to accept any
|
||
|
power-of-two bits per pixel (up to the maximum) at any allowed screen
|
||
|
size. This allows users to always change the pixel depth without
|
||
|
altering the screen size, and to alter the screen size without
|
||
|
changing the pixel depth.
|
||
|
|
||
|
Some systems, like X windows, don't have a fixed list of screen sizes
|
||
|
from which Executor can select. In those cases, the list of canonical
|
||
|
sizes will contain two elements, the minimum and the maximum, and
|
||
|
continuous_range_p will be TRUE. `vdriver_acceptable_mode' will
|
||
|
return TRUE for acceptable sizes in between the minimum and the
|
||
|
maximum. This is useful when the user wants to resize Executor's
|
||
|
screen to some arbitrary size by using facilities in the host's window
|
||
|
system.
|
||
|
|
||
|
The functions in this file are prototyped in "vdriver.h". vdriver.h
|
||
|
#include's "host_vdriver.h" before prototyping any of these functions,
|
||
|
so that host_vdriver.h may replace some of them with macros on systems
|
||
|
where that is appropriate. vdriver.h will not prototype any function
|
||
|
that is defined as a macro by host_vdriver.h.
|
||
|
|
||
|
|
||
|
-- Function: boolean_t vdriver_init (int MAX_WIDTH, int MAX_HEIGHT,
|
||
|
int MAX_BPP, boolean_t FIXED_P,
|
||
|
int *argc, char *argv[])
|
||
|
`vdriver_init' must be called exactly once, before any other
|
||
|
vdriver routines. It is responsible for allocating memory to
|
||
|
hold the frame buffer (if necessary) and performing any other
|
||
|
host-specific initialization.
|
||
|
|
||
|
The frame buffer's base address can never change, so the
|
||
|
parameters to this function are hints that specify the biggest
|
||
|
mode that might ever be requested so that sufficient memory can
|
||
|
be allocated initially. The allocated frame buffer should
|
||
|
usually be big enough to support either that mode or the biggest
|
||
|
mode the hardware can physically support, but it need not be.
|
||
|
Each row of the frame buffer must start on a 32-bit boundary
|
||
|
(i.e. the starting addresses must be divisible by four).
|
||
|
|
||
|
If MAX_WIDTH is zero, this function should choose a largest size
|
||
|
and bpp in a host-defined way and allocate frame buffer memory
|
||
|
appropriately. For example, if MAX_WIDTH == 0 and the graphics
|
||
|
hardware can only support a window at most 800x600 with at most 4
|
||
|
bits per pixel, 800x600x4 should be used. If the hardware can
|
||
|
support 3000x3000x8, this function may decide to choose a smaller
|
||
|
maximum size and stick with it.
|
||
|
|
||
|
If FIXED_P is TRUE, then the graphics mode will never be set to
|
||
|
any size other than MAX_WIDTHxMAX_HEIGHTxMAX_BPP. Fixing these
|
||
|
parameters can sometimes enable speedups not otherwise available,
|
||
|
but at the cost of losing the ability to do dynamic mode sets.
|
||
|
It is of course safe to assume this flag is FALSE. It is an
|
||
|
error for MAX_WIDTH to be zero and for FIXED_P to be true.
|
||
|
|
||
|
ARGC and ARGV specify command line options given to the program.
|
||
|
The vdriver can ignore these parameters, but if it wants to process
|
||
|
any of these arguments, it should remove them from argv and adjust
|
||
|
argc appropriately.
|
||
|
|
||
|
Frame buffer memory need not be initialized here. In general,
|
||
|
you should avoid touching frame buffer memory that might not end
|
||
|
up getting used, since this will be more efficient on systems
|
||
|
that lazily allocate memory pages.
|
||
|
|
||
|
`vdriver_init' should not set up any default graphics mode.
|
||
|
`vdriver_set_mode' will take care of that.
|
||
|
|
||
|
`vdriver_init' should return TRUE if successful, FALSE if
|
||
|
it failed to open the display (which will be a fatal error
|
||
|
for Executor).
|
||
|
|
||
|
-- Function: void vdriver_shutdown (void)
|
||
|
|
||
|
`vdriver_shutdown' is responsible for cleaning up after the
|
||
|
vdriver routines and returning the display back to a state
|
||
|
appropriate for Executor to exit. For convenience, this function
|
||
|
can be called more than once; however, once it is called, no
|
||
|
vdriver routine other than this one should be called. This
|
||
|
routine must be called once before Executor exits.
|
||
|
|
||
|
-- Function: boolean_t vdriver_acceptable_mode_p (int WIDTH, int HEIGHT,
|
||
|
int BPP,
|
||
|
boolean_t EXACT_MATCH_P)
|
||
|
Returns TRUE if the given mode will work if passed to
|
||
|
`vdriver_set_mode', else FALSE. If EXACT_MATCH_P is true, this
|
||
|
function will only return TRUE if `vdriver_set_mode' will
|
||
|
accept the mode without adjusting the screen size at all.
|
||
|
If WIDTH, HEIGHT, or BPP are zero, they are replaced with default
|
||
|
values as described in `vdriver_set_mode'.
|
||
|
|
||
|
-- Function: boolean_t vdriver_set_mode (int WIDTH, int HEIGHT, int BPP)
|
||
|
`vdriver_set_mode' does the dirty work of actually setting up a
|
||
|
particular graphics mode. BPP must be a power of two between 1
|
||
|
and the maximum bpp returned by vdriver_mode_info, and must be
|
||
|
honored. If WIDTHxHEIGHT is a mode listed as canonical by
|
||
|
`vdriver_mode_info', it must be honored exactly. Otherwise, this
|
||
|
function should try to choose the smallest mode which is at least
|
||
|
as large as that specified by the caller. If even that is not
|
||
|
large enough, this function should choose the largest available
|
||
|
mode. The actual screen size chosen by this function can and
|
||
|
should be determined by calling `vdriver_frame_buffer', since it
|
||
|
may not be exactly what was passed in.
|
||
|
|
||
|
If WIDTH, HEIGHT, or BPP is zero, it is replaced with the current
|
||
|
value for that parameter (if a mode has been set) or, if no mode
|
||
|
has yet been set, it is replaced with an host-defined default value.
|
||
|
|
||
|
This function need not redraw the screen, and is entitled to
|
||
|
leave the screen in a "garbage" state. The caller is responsible
|
||
|
for properly redrawing the frame buffer after a mode set.
|
||
|
|
||
|
This function returns TRUE if a mode set was achieved, FALSE
|
||
|
otherwise (in which case the mode should remain unchanged).
|
||
|
|
||
|
-- Function: void vdriver_set_colors (int FIRST_COLOR, int NUM_COLORS,
|
||
|
const ColorSpec *COLOR_ARRAY)
|
||
|
`vdriver_set_colors' is called when the color table of the display
|
||
|
has changed. The colors for pixel values:
|
||
|
FIRST_COLOR ... FIRST_COLOR + NUM_COLORS - 1
|
||
|
are set to the values specified by:
|
||
|
COLOR_ARRAY[0] ... COLOR_ARRAY[NUM_COLORS - 1], respectively.
|
||
|
NOTE: For convenience, each ColorSpec is assumed to store its values
|
||
|
in big endian byte order. That way you can just pass a real
|
||
|
color table to this function.
|
||
|
|
||
|
Of course, the graphics hardware may not actually have a color
|
||
|
table, but the vdriver must at least provide the illusion of one.
|
||
|
All changed color values must be visible to the user before this
|
||
|
function returns or after `vdriver_flush_display' is next called.
|
||
|
|
||
|
-- Function: int vdriver_update_screen (int top, int left, int bottom,
|
||
|
int right, boolean_t cursor_p)
|
||
|
`vdriver_update_screen' transfers the specified rectangle from the
|
||
|
internal frame buffer to the actual graphics hardware. If the
|
||
|
rectangle exceeds the bounds of the frame buffer, it will be
|
||
|
pinned to fit within it. CURSOR_P should only be TRUE when it
|
||
|
is the cursor being drawn to the screen. Most implementations
|
||
|
can ignore this flag, but DOS uses it to tell whether or not the
|
||
|
cursor got overwritten by an update and needs to be redisplayed.
|
||
|
You almost always want to pass FALSE for this flag when calling
|
||
|
this routine.
|
||
|
|
||
|
The return value is implementation-dependent and should be ignored.
|
||
|
|
||
|
The transferred information need not be visible to the user by
|
||
|
the time this function exits. `vdriver_update_screen' may only
|
||
|
queue up the display with the host's windowing system. To
|
||
|
guarantee that the information is visible to the user, call
|
||
|
`vdriver_flush_display'
|
||
|
|
||
|
-- Function: int vdriver_update_screen_rects (int NUM_RECTS,
|
||
|
const vdriver_rect_t *R,
|
||
|
boolean_t CURSOR_P)
|
||
|
Like vdriver_update_screen, but can update many rectangles at
|
||
|
once. Calling this may be more efficient than making separate
|
||
|
calls to `vdriver_update_screen'.
|
||
|
|
||
|
-- Function: void vdriver_flush_display (void)
|
||
|
This function guarantees that any updates from
|
||
|
`vdriver_update_screen' will be made visible to the user "soon",
|
||
|
even if no further vdriver calls are made. The intent of this
|
||
|
function is that calling it frequently will make graphics animate
|
||
|
smoothly, instead of queueing up with the window server and
|
||
|
getting blasted out in chunks. This is only relevant for hosts
|
||
|
that talk to a window server, but it's always safe to call it.
|
||
|
|
||
|
-- Function: void vdriver_system_busy (int BUSY_P)
|
||
|
This function is sometimes called when Executor is busy and wants
|
||
|
to inform the user that it is actually doing something and not
|
||
|
just hung. During such times, it may be called extremely frequently,
|
||
|
so this function should be very fast. If BUSY_P is true,
|
||
|
the system is still busy. If it's FALSE, the system is no longer
|
||
|
busy. This function is optional and calls to it may be ignored on
|
||
|
any system; if you want calls to be ignored, don't write this
|
||
|
function and instead put this line in host_vdriver.h:
|
||
|
#define vdriver_system_busy 0
|
||
|
|
||
|
-- Function: vdriver_accel_result_t
|
||
|
vdriver_accel_rect_fill (int TOP, int LEFT, int BOTTOM,
|
||
|
int RIGHT, uint32 COLOR)
|
||
|
|
||
|
This function optionally fills in the specified screen rectangle
|
||
|
with the given solid COLOR. COLOR is a pixel for the internal
|
||
|
frame buffer (if any), and may not correspond to the host
|
||
|
screen's color space. The vdriver is responsible for making that
|
||
|
translation.
|
||
|
|
||
|
The vdriver is not allowed to update the screen "out of order".
|
||
|
All dirty rects must be flushed to the screen before any
|
||
|
accelerated drawing can take place.
|
||
|
|
||
|
This function returns a value indicating what effect it had:
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
VDRIVER_ACCEL_NO_UPDATE,
|
||
|
VDRIVER_ACCEL_FULL_UPDATE,
|
||
|
VDRIVER_ACCEL_HOST_SCREEN_UPDATE_ONLY
|
||
|
} vdriver_accel_result_t;
|
||
|
|
||
|
VDRIVER_ACCEL_NO_UPDATE means no action was performed, and
|
||
|
the usual blitting and dirty rect mechanisms should be
|
||
|
employed.
|
||
|
VDRIVER_ACCEL_FULL_UPDATE means that both the host screen
|
||
|
and internal frame buffer have been fully updated, and no
|
||
|
more work needs to be done.
|
||
|
VDRIVER_ACCEL_HOST_SCREEN_UPDATE_ONLY means that the host screen
|
||
|
now has the correct data, but the internal frame buffer still
|
||
|
needs to be updated. The internal frame buffer will be updated
|
||
|
by the usual mechanisms, but no dirty rect will be accrued for
|
||
|
that update because the screen already has the correct
|
||
|
information.
|
||
|
|
||
|
If the vdriver doesn't support this function, the easiest way
|
||
|
to note that is to add this line to host_vdriver.h:
|
||
|
|
||
|
#define vdriver_accel_rect_fill(t, l, b, r, c) VDRIVER_ACCEL_NO_UPDATE
|
||
|
|
||
|
It may be advantageous for the vdriver to decide that using an
|
||
|
accelerated mechanism is a lose and return
|
||
|
VDRIVER_ACCEL_NO_UPDATE. For example, this might make sense if
|
||
|
the rectangle is very small or if it overlaps an existing dirty
|
||
|
rectangle.
|
||
|
|
||
|
-- Function: vdriver_accel_result_t
|
||
|
vdriver_accel_rect_scroll (int TOP, int LEFT, int BOTTOM,
|
||
|
int RIGHT, int DX, int DY)
|
||
|
|
||
|
The specified rectangle is copied on the screen DX pixels to the
|
||
|
right and DY pixels down from its current location. DX and DY may
|
||
|
each be negative, 0, or positive. Overlapping data must be
|
||
|
handled correctly. The return value and semantics are otherwise
|
||
|
analagous to those of `vdriver_accel_rect_fill'.
|
||
|
|
||
|
-- Function: void vdriver_accel_wait (void)
|
||
|
|
||
|
This function waits until it is safe to access the frame buffer's
|
||
|
pixels directly and then returns. For example, an accelerated
|
||
|
SVGA vdriver might have the SVGA board fill in a rectangle in
|
||
|
VRAM. You are not guaranteed to get the correct pixel values from
|
||
|
the frame buffer until this rect fill has completed, so you must
|
||
|
wait until the rect fill is done.
|
||
|
|
||
|
This call is only useful on systems where the bitmap being
|
||
|
modified by the accelerator is the same as the bitmap that
|
||
|
Executor references directly. This is not the case under X
|
||
|
windows, for example. Most vdrivers will just want to put:
|
||
|
|
||
|
#define vdriver_accel_wait()
|
||
|
|
||
|
in host_vdriver.h.
|