Like other drivers, drivers for graphics cards are dynamically loaded modules --but they're loaded by the Application Server, the software component that's responsible for graphics operations, not by the kernel. Because they're add-on modules, these drivers share some similarities with other drivers:
Because the host module is the Application Server rather than the kernel, graphics card drivers must follow protocols that the Server defines, not those that the kernel imposes on other drivers. The entry points, exported functions, and installation directory are all specific to graphics card drivers. Therefore, if you're developing a driver for a graphics card, disregard the preceding sections of this chapter dealing with kernel drivers and follow the rules outlined in this section instead.
Control of a graphics card driver resides only with the host module; there are no functions (like open() or ioctl()) through which a program can control the driver.
However, applications can get direct access to the graphics card through the BWindowScreen class in the Game Kit. Access is provided by making a clone of the graphics card driver and attaching it to the application. The original driver remains running as part of the Application Server, but its connection to the screen is suspended while the clone is active.
Every graphics card driver must implement a function called control_graphics_card(). This is the Application Server's main entry point into the driver; it's the function the Server calls to set up the driver, query it for information, pass it configuration instructions, and generally control what it does. It has the following syntax:
long control_graphics_card(ulong op, void *data)
The first argument, op, names the operation the driver is requested to perform. The second argument, data, points either to some information that will help the driver carry out the request or to a location where it should write some information as a result of the operation. The exact type of data in either case depends on the nature of the operation. The op and data arguments are inextricably linked.
The return value is an error code. In general, the control function should return B_NO_ERROR if it can successfully respond to a particular op request, and B_ERROR if it cannot. It should also respond B_ERROR to any undefined op code requests it doesn't understand.
There are seventeen control operations that a driver's control_graphics_card() function can be requested to perform (seventeen op codes defined in device/GraphicsCard.h). Nine of these operations give the Application Server general control over the driver. The other eight concern the cloning of the driver and the direct control of the frame buffer through the Game Kit. Those operations are discussed under Control Operations for Cloning the Driver and Control Operations for Manipulating the Frame Buffer below. This sections lists and discusses the nine main control operations.
This op code requests the driver to open and initialize the graphics card specified by the data argument. If the driver can open the card, it should do so and return B_NO_ERROR. If it can't, it should return B_ERROR . The data pointer refers to a graphics_card_spec structure with the following fields:
void *screen_base | The beginning of memory on the graphics card. The driver can locate the frame buffer somewhere in this memory, but not necessarily at the base address. |
void *io_base | The base address for the I/O registers that control the graphics card. Registers are addressed by 16-bit offsets from this base address. |
ulong vendor_id | The number that identifies the manufacturer of the graphics chip on the card. |
ulong device_id | A number that identifies the particular graphics chip of that manufacturer. |
If the driver can open the graphics card, it should take the opportunity to initialize any data structures it might need. However, it should wait for further instructions--particularly a B_CONFIG_GRAPHICS_CARD request--before initializing the frame buffer or turning on the video display.
If the driver returns B_ERROR, indicating that it's not the driver for the specified graphics card, it will immediately get a request to close the card as a prelude to being unloaded.
This operation notifies the graphics card driver that it's about to be unloaded. The data argument is meaningless (it doesn't point to any valid information). The Application Server ignores the return value and unloads the driver no matter what.
This operation is used to set up the palette of colors that can be displayed when the frame buffer is 8 bits deep. It requests the driver to place a particular color at a particular position in the list of 256 colors that's kept on the card. The data argument points to a indexed_color structure with two pieces of information:
long index | The index of the color in the list. This value is used as the color value in the B_COLOR_8_BIT color space. Indices begin at 0. |
rgb_color color | The full 32-bit color that should be associated with the index. |
A driver can expect a series of B_SET_INDEXED_COLOR requests soon after it is opened. It might get subsequent requests when an application (through the Game Kit) modifies the color list, and when the game returns control to the Application Server.
This op code requests control_graphics_card() to supply the Application Server with an array of function pointers. Each pointer is to a hook function that the Server can call to carry out a specific graphics task. A total of B_HOOK_COUNT (48 at present) pointers must be written, although only a quarter of that number are currently used. The full array should be written to the location the data argument points to, with NULL values inserted for undefined functions.
A later section, Hook Functions , describes the hook functions, the tasks they should perform, their arguments and return types, and their positions in the array.
A driver can expect a B_GET_GRAPHICS_CARD_HOOKS request soon after it is opened, and again any time the screen configuration changes. The hook functions can be tailored to a specific screen dimension and depth.
This op code requests the control_graphics_card() function to supply information about the driver and the current configuration of the screen. The data argument points to a graphics_card_info structure where it should write this information. This structure contains the following fields:
short version | The version of the Be architecture for graphics cards that the driver was designed to work with. The current version is 2. |
short id | An identifier for the driver, understood in relation to the version number. The Application Server doesn't check this number; it can be set to any value you desire. |
void *frame_buffer | A pointer to the first byte of the frame buffer. |
char rgba_order[4] | The order of color components as the bytes for those components are stored in video memory (in the frame buffer). This array should arrange the characters 'r' (red), 'g' (green), 'b' (blue), and 'a' (alpha) in the order in which those components are intermeshed for each pixel in the frame buffer; a typical order is "bgra". This field is valid only for screen depths of 32 bits per pixel. |
short flags | A mask containing flags that describe the ability of the graphics card driver to perform particular tasks. |
short bits_per_pixel | The depth of the screen in bits per pixel. Only 32-bit (B_RGB_32_BIT) and 8-bit (B_COLOR_8_BIT) depths are currently supported. |
long bytes_per_row | The offset, in bytes, between two adjacent rows of pixel data in the frame buffer (the number of bytes assigned to each row). |
short width | The width of the frame buffer in pixels (the number of pixel columns it defines). |
short height | The height of the frame buffer in pixels (the number of pixel rows it defines). |
Three constants are currently defined for the flags mask:
B_CRT_CONTROL | Indicates that the driver is able to control, to any extent, the position or the size of the CRT display on the monitor--that there's a provision for controlling the CRT through software, not just hardware. |
B_GAMMA_CONTROL | Indicates that the driver is able to make gamma corrections that compensate for the particular characteristics of the display device. |
B_FRAME_BUFFER_CONTROL | Indicates that the driver allows clients to set arbitrary dimensions for the frame buffer and to control which portion of the frame buffer (the display area) is mapped to the screen. |
The driver will receive frequent B_GET_GRAPHICS_CARD_INFO requests. The graphics_card_info structure it supplies should always reflect the values currently in force.
This op code asks control_graphics_card() to place the current refresh rate, as well as the maximum and minimum rates, in the refresh_rate_info structure referred to by the data pointer. This structure contains the following fields:
float min | The minimum refresh rate that the graphics card is capable of, given the current configuration. |
float max | The maximum refresh rate that the graphics card is capable of, given the current configuration. |
float current | The current refresh rate. |
All values should be provided in hertz.
This op code requests the driver to supply a mask containing all possible configurations of the screen space--all supported combinations of pixel depth and dimensions of the pixel grid. The mask is formed from the following constants--which are defined in interface/InterfaceDefs.h--and is written to the location indicated by the data pointer:
For example, if the mask includes B_8_BIT_1600x1200, the driver can configure a frame buffer that's simultaneously 8 bits deep (the B_COLOR_8_BIT color space), 1,600 pixel columns wide, and 1,200 pixel rows high. The mask should include all configurations that the graphics card is capable of supporting.
< The Application Server currently doesn't permit depths of 16 bits. >
(InterfaceDefs.h defines one other screen space, B_8_BIT_640x400, but this is reserved for the default "supervga" driver provided by Be.)
This op code asks the control function to configure the display according to the values set in the graphics_card_config structure that the data argument points to. This structure contains the following fields:
ulong space | The size of the pixel grid on-screen and the depth of the frame buffer in bits per pixel. This field will be one of the constants listed above for the B_GET_SCREEN_SPACES control operation. |
float refresh_rate | The refresh rate of the screen in hertz. |
uchar h_position | The horizontal position of the CRT display on the monitor. |
uchar v_position | The vertical position of the CRT display on the monitor. |
uchar h_size | The horizontal size of the CRT display on the monitor. |
uchar v_size | The vertical size of the CRT display on the monitor. |
The most important configuration parameter is the space field. The driver should reconfigure the screen to the depth and size requested and return B_NO_ERROR. If it can't carry out the request, it should return B_ERROR.
Failure to comply with the other fields of the graphics_card_config structure should not result in a B_ERROR return value. The driver should come as close as it can to the requested refresh rate. The last four fields are appropriate only for drivers that reported that they could control the positioning of the CRT display (by setting the B_CRT_CONTROL flag in response to a B_GET_GRAPHICS_CARD_INFO request).
The values for the four CRT configuration fields range from 0 through 100, with 50 as the default. Values of less than 50 for h_position and v_position should move the display toward the left and top; those greater than 50 should move it to the right and bottom. Values of less than 50 for h_size and v_size should make the display narrower and shorter, squeezing it into a smaller area; values greater than 50 should make it wider and taller.
This operation asks the driver to set up a table for adjusting color values to correct for the peculiarities of the display device. The data argument points to a screen_gamma structure with gamma corrections for each color component. It contains the following three fields:
uchar red[256] | Mappings for the red component. |
uchar green[256] | Mappings for the green component. |
uchar blue[256] | Mappings for the blue component. |
Each field is a component-specific array. The stated color value is used as an index into the array; the value found at that index substitutes for the stated value. For example, if the value at blue[152] is 154, all blue component values of 152 should be replaced by 154, essentially adding to the blueness of the color as displayed.
Only drivers that indicated they could make gamma corrections (by setting the B_GAMMA_CONTROL flag in response to a B_GET_GRAPHICS_CARD_INFO request) need to respond to B_SET_SCREEN_GAMMA requests.
< The control function is currently not requested to perform this operation. >
Normally, an application's access to the screen is mediated by the Application Server. The application can draw in windows the Server provides through BView objects with graphics environments kept by the Server. The Application Server doesn't let applications communicate directly with the graphics card driver.
To give an application direct access to the screen, as the Game Kit does, the Application Server must get out of the way and the driver must be attached directly to the application. This is accomplished, not by detaching the driver from the Server, but by making a copy of it--a clone--for the application. While the clone is active, the Server suspends its graphic operations.
Graphics card drivers must therefore be prepared to clone themselves --to respond to the four control operations described below. Two of the requests are made of a driver the Application Server has loaded, and two are made of the clone.
This op code requests control_graphics_card() to write information about the current state of the driver to the location referred to by the data pointer. This request is made of a driver loaded by the Application Server; the information it provides is passed to the clone (in a B_SET_CLONED_GRAPHICS_CARD request) so that the clone can duplicate the state of the driver.
The driver should package the requested information in a data structure it defines; it can be any structure you desire. The package should include all the driver's variable settings --everything from the current configuration of the screen to the location of the frame buffer in card memory. For example, if the structure is called info_for_clone , driver code might look something like this:
case B_GET_INFO_FOR_CLONE: ((info_for_clone *)data)->depth = info.bits_per_pixel; ((info_for_clone *)data)->height = info.height; ((info_for_clone *)data)->width = info.width; ((info_for_clone *)data)->row_byte = info.bytes_per_row; ((info_for_clone *)data)->frame_base = info.frame_buffer; ((info_for_clone *)data)->io_base = spec.io_base; ((info_for_clone *)data)->available_mem = unused_memory; ((info_for_clone *)data)->refresh_rate = rate.current; . . . break;
Of course, information that's kept on the card itself, such as the current color map, does not have to be duplicated for the clone.
Since an attempt is made to keep the driver and its clone in the same state, you can expect numerous B_GET_INFO_FOR_CLONE requests while the clone is active.
This operation requests the driver to inform the Application Server how many bytes of information it will provide in response to a B_GET_INFO_FOR_CLONE request. The control function should write the size of the data structure as a long integer in the location that the data pointer refers to. For example:
*((long *)data) = sizeof(info_for_clone);
This information enables the Application Server to allocate enough memory to hold the data it will receive.
This operation sets up the clone. In the data pointer, it passes the clone's control_graphics_card() function all the information that the driver provided in response to a B_GET_INFO_FOR_CLONE request. The clone should read the information from the data pointer and set all the parameters that are provided.
The clone receives a B_SET_CLONED_GRAPHICS_CARD request instead of a B_OPEN_GRAPHICS_CARD notification when it first is created and loaded by the Game Kit. It subsequently will receive the request many more times --whenever it must be synchronized with the driver loaded by the Application Server.
This op code is passed to the clone's control_graphics_card() function to signal that the clone is about to be unloaded. The clone receives this notification instead of B_CLOSE_GRAPHICS_CARD . The data pointer should be ignored.
The BWindowScreen class of the Game Kit defines a set of four functions that give applications more or less arbitrary control over the frame buffer:
ProposeFrameBuffer()
SetFrameBuffer()
SetDisplayArea()
MoveDisplayArea()
Each of these functions translates to an identically named operation that the driver's control_graphics_card() function can be requested to perform. Graphics card drivers announce their ability to respond to these requests by including a constant in the flags field of the graphics_card_info structure they report in response to a B_GET_GRAPHICS_CARD_INFO request. The constant is B_FRAME_BUFFER_CONTROL.
All four of the control operations use the same structure to pass data to the driver, though they don't all make use the same set of fields within the structure. The structure is called frame_buffer_info and it contains the following fields:
short bits_per_pixel | The depth of the frame buffer; the number of bits assigned to a pixel. |
short bytes_per_row | The number of bytes that are used to store one row of pixel data in the frame buffer. |
short width | The width of the frame buffer in pixels (the total number of pixel columns). |
short height | The height of the frame buffer in pixels (the total number of pixel rows. |
short display_width | The width of the screen display in pixels (the number of pixel columns displayed on-screen). |
short display_height | The height of the screen display in pixels (the number of pixel rows displayed on-screen). |
short display_x | The pixel column in the frame buffer that's mapped to the leftmost column of pixels on the screen, where columns are indicated by a left-to-right index beginning with 0. |
short display_y | The pixel row in the frame buffer that's mapped to the topmost row of pixels on the screen, where rows are indicated by a top-to-bottom index beginning with 0. |
The first four fields of this structure are identical to the last four of the graphics_card_info structure. However, graphics_card_info is used only to return information to the host, whereas frame_buffer_info can pass requests to the driver. It's possible for those four fields to be set to arbitrary values, so the frame buffer isn't limited to the standard configurations of depth, width, and height described under B_GET_SCREEN_SPACES above. (Of course, the driver can reject proposed configurations that it can't accommodate.)
The last four fields of the frame_buffer_info structure distinguish between the frame buffer itself and the part of the frame buffer that's displayed on-screen--the display area . This distinction permits the display area to be moved and resized on a (possibly) much larger area defined by the frame buffer. For buffered drawing, the frame buffer can be partitioned into discrete sections and the display area moved from one to another. For hardware scrolling, the display area can be moved repeatedly by small increments. For simulated zooming, it's size can be incrementally reduced or expanded.
Both areas are defined by a width (the number of pixel columns the area includes) and a height (the number of pixel rows). The display area is located in the frame buffer by the index to the column (display_x) and row (display_y ) of its left top pixel. See the SetDisplayArea() function on page 14 in The Game Kit chapter for an illustration
The four operations that exercise control over the frame buffer are described below.
This op code proposes a particular width and depth for the frame buffer to the driver. The only valid fields of the frame_buffer_info structure passed through the data pointer are bits_per_pixel and width. If the driver can configure a frame buffer with those dimensions, it should fill in the rest of frame buffer description and return B_NO_ERROR. In the bytes_per_row field, it should write the minimum number of bytes required to store each row of pixel data given the proposed depth and width. In the height field, it should report the maximum number of pixel rows it can provide given the other dimensions. The fields of the frame_buffer_info structure that describe the display area can be ignored.
The driver should not actually configure the frame buffer in response to the proposal; it should wait for a B_SET_FRAME_BUFFER instruction. B_PROPOSE_FRAME_BUFFER merely tests the driver's capabilities.
If the driver can't accommodate a frame buffer with the proposed dimensions, it should place -1 in the bytes_per_row and height fields and return B_ERROR.
This operation requests the driver's control_graphics_card() function to configure the frame buffer according to the description in the frame_buffer_info structure passed through the data pointer. All fields in the structure contain meaningful values and should be read.
The specified configuration ought to have been previously tested through a B_PROPOSE_FRAME_BUFFER operation, and therefore should be one the driver can accommodate. If it's not, control_graphics_card() should do nothing and return B_ERROR . If it can configure the frame buffer according to the request, it should return B_NO_ERROR.
This op code requests the control function to set the display area, as specified by the last four fields of the frame_buffer_info structure passed through the data pointer. The other fields should be ignored.
If the driver can map the display area as requested, control_graphics_card() should return B_NO_ERROR. Otherwise, it should return B_ERROR.
This op code requests the control function to move the display area without resizing it, as specified by the display_x and display_y fields of the frame_buffer_info structure that the data pointer refers to. The other fields of the structure should be ignored.
The driver should move the display area so that the left top pixel displayed on-screen is the one located at (display_x, display_y) in the frame buffer and return B_NO_ERROR. If it can't move the display area to that location, it should return B_ERROR.
A graphics card driver can implement hook functions to manage the cursor and perform particular, well-defined drawing tasks on behalf of the Application Server. Drivers should implement as many of these functions as they can to speed on-screen graphics performance.
The driver informs the Application Server about these functions soon after it's loaded when its control_graphics_card() function receives a B_GET_GRAPHICS_CARD_HOOKS request (see page 79 above). In response to this request, the driver needs to place an array of B_HOOK_COUNT (48) function pointers at the location the data argument points to. The request is repeated whenever the configuration of the frame buffer (its dimensions and depth) changes. The driver can provide hook functions specific to a particular configuration.
Currently, only the first 12 slots in the array are defined. These functions fall into four groups:
Each undefined slot in the array of hook functions should be filled with a NULL pointer. Similarly, the driver should place a NULL value in any defined slot if it can't usefully implement the function.
Although all pointers in the array are declared to be of type graphics_card_hook ,
typedef void (*graphics_card_hook)(void)
each function has its own set of arguments and returns a meaningful error value, declared as a long. The functions should be implemented to return B_NO_ERROR if all goes well and they're successful in performing the task at hand, and B_ERROR if unsuccessful. It's better by far to place a NULL pointer in the array than to define a function that always returns B_ERROR.
The coordinate system that the Application Server assumes for all hook functions equates one coordinate unit to one screen pixel. The origin is at the pixel in the left top corner of the screen. In other words, an x coordinate value is a left-to-right index to a pixel column and a y coordinate value is a top-to-bottom index to a pixel row.
The following sections discuss each of the hook functions in turn.
The function at index 0 is called to set the cursor image. It has the following syntax:
long define_cursor(uchar *xorMask, uchar *andMask, long width, long height, long hotX, long hotY)
The first two arguments, xorMask and andMask, together define the shape of the cursor. Each mask has a depth of 1 bit per pixel, yielding a total of four possible values for each cursor pixel. They should be interpreted as follows:
xorMask | andMask | meaning |
---|---|---|
0 | 0 | Transparency; let the color of the screen pixel under the cursor pixel show through. |
1 | 0 | Inversion; invert the color of the screen pixel. |
0 | 1 | White; replace the screen pixel with a white cursor pixel. |
1 | 1 | Black; replace the screen pixel with a black cursor pixel. |
Inversion in its simplest form is accomplished by taking the complement of the color index or of each color component. For example:
color = 255 - color;
< However, the results of inversion may not be very pleasing given the current color map. Therefore, none of the Be-defined cursors will use inversion until a future release. It would be better for your drivers to avoid it as well. The color map will be corrected in a future release. >
The second two arguments, width and height, determine the size of the cursor image in pixels. Currently, the Application Server supports only one cursor size; they must be 16 pixels wide and 16 pixels high.
The (hotX, hotY) arguments define the hot pixel in the image --the pixel that's used to report the location of the cursor. They assume a coordinate system where the pixel at the left top corner of the image is (0, 0) and the one at the right bottom corner is (15, 15).
This function should change the cursor image on-screen, if the cursor is currently displayed on-screen. But if the cursor is hidden, it should not show it. Wait for explicit calls to the next two functions to move the cursor or change its on-screen status.
The function at index 1 changes the location of the cursor image. It should expect two arguments:
long move_cursor(long screenX, long screenY)
In response, this function should move the cursor so that its hot pixel corresponds to (screenX, screenY).
The function at index 2 shows and hides the cursor:
long show_cursor(bool flag)
If the flag argument is TRUE, this function should show the cursor image on-screen; if it's FALSE, it should remove the cursor from the screen.
< If this function is asked to show the cursor before the function at index 1 is called, it should show it at (0, 0). >
The function at index 3 draws a straight line in the B_COLOR_8_BIT color space. It takes 10 arguments:
long draw_line_with_8_bit_depth(long startX, long startY, long endX, long endY, uchar colorIndex, bool clipToRect, short clipLeft, short clipTop, short clipRight, short clipBottom)
The first four arguments define the starting and ending points of the line; it begins at (startX, startY) and ends at (endX, endY). Both points are included within the line. The fifth argument, colorIndex, is the color of the line; it's an index into the map of 256 colors.
< In the current release, the second and third arguments are inverted; the first four arguments are ordered: startX, endX, startY, endY. >
If the sixth argument, clipToRect, is TRUE, the function should draw only the portion of the line that lies within the clipping rectangle defined by the last four arguments. The sides of the rectangle are included within the drawing area--they're inside the visible region; everything outside the rectangle is clipped.
If clipToRect is FALSE, the final four arguments should be ignored.
This function should draw a line of minimal thickness, which means a line no thicker than one pixel at any given point. If the line is more vertical than horizontal, only one pixel per row between the start and end points should be colored; if it's more horizontal than vertical, only one pixel per column should be colored.
The function at index 4 is like the one at index 3, except that it draws a line in the B_RGB_32_BIT color space:
long draw_line_with_32_bit_depth(long startX, long startY, long endX, long endY, ulong color, bool clipToRect, short clipLeft, short clipTop, short clipRight, short clipBottom)
The only difference between this and the previous function is the color argument. Here the color is specified as a full 32-bit quantity with 8-bit red, green, blue, and alpha components. The color argument arranges the components in the order that the driver asked for them (in the rgba_order field of the graphics_card_info structure that it provided in response to a B_GET_GRAPHICS_CARD_INFO request).
Otherwise, this function should work just like the one at index 3. < And like the function at index 3, the second and third arguments are inverted in the current release; the first four arguments are ordered: startX, endX, startY, endY. >
The function at index 5 should be implemented to fill a rectangle with a color specified by its index:
long draw_rect_with_8_bit_depth(long left, long top, long right, long bottom, uchar colorIndex)
The left, top, right, and bottom sides of the rectangle should be included in the area being filled.
The function at index 6, like the one at index 5, fills a rectangle:
long draw_rect_with_32_bit_depth(long left, long top, long right, long bottom, ulong color)
The color value contains the four color components--red, green, blue, and alpha --arranged in the natural order for the device (the same order that the driver recorded in the rgba_order field of the graphics_card_info structure it provided to the Application Server).
The sides of the rectangle should be included in the area being filled.
The function at index 7 should copy pixel values from a source rectangle on-screen to a destination rectangle:
long blit(long sourceX, long sourceY, long destinationX, long destinationY, long width, long height)
The left top corner of the source rectangle is the pixel at (sourceX , sourceY). The left top pixel of the destination rectangle is at ( destinationX, destinationY). Both rectangles are width pixels wide and height pixels high, and both are guaranteed to always lie entirely on-screen. The width and height arguments will always contain positive values.
The function at index 8 should draw an array of lines in the B_COLOR_8_BIT color space. It takes the following set of arguments:
long draw_array_with_8_bit_depth(indexed_color_line *array, long numItems, bool clipToRect, short clipLeft, short clipTop, short clipRight, short clipBottom)
The line array holds a total of numItems. Each item is specified as an indexed_color_line structure, which contains the following fields:
short x1 | The x coordinate of one end of the line. |
short y1 | The y coordinate of one end of the line. |
short x2 | The x coordinate of the other end of the line. |
short y2 | The y coordinate of the other end of the line. |
uchar color | The color of the line, expressed as an index into the color map. |
The function should draw each line from (x1, y1) to (x2, y2) using the color specified for that line.
If the clipToRect flag is TRUE, nothing should be drawn that falls outside the clipping rectangle defined by the final four arguments. The sides of the rectangle are included in the visible region. If clipToRect is FALSE, the final four arguments should be ignored.
Each line in the array should be drawn with the minimal possible thickness, as described under Index 3: Drawing a Line with an 8-Bit Color above.
The function at index 9 has the same syntax as the one at index 8, except for the first argument:
long draw_array_with_32_bit_depth(rgb_color_line *array, long numItems, bool clipToRect, short clipLeft, short clipTop, short clipRight, short clipBottom)
Here, each line in the array is specified as an rgb_color_line structure, rather than as an indexed_color_line. The two structures differ only in how the color is specified:
short x1 | The x coordinate of one end of the line. |
short y1 | The y coordinate of one end of the line. |
short x2 | The x coordinate of the other end of the line. |
short y2 | The y coordinate of the other end of the line. |
rgb_color color | The color of the line, expressed as a full 32-bit value. |
In all other respects, this function should work like the one at index 8.
The Application Server calls the function at index 10 to synchronize its activities with the driver. It takes no arguments:
long sync(void)
This function simply returns when the driver is finished modifying the frame buffer --when it's finished touching video RAM.
If any of the other hook functions works asynchronously--if it returns before the drawing it's asked to do is complete--the synchronizing function should wait until all drawing operations have been completed before it returns. The return value is not important; the Application Server ignores it.
However, if all the other hook functions are synchronous--if they don't return until the drawing is finished--this function would simply return; it would be empty. It's better not to implement such a function. It's preferable to put a NULL pointer at index 10 and save the Application Server a function call.
Therefore, your driver should implement this function only if at least one of the other hook functions draws asynchronously.
The function at index 11 should invert the colors in a rectangle. It has the following syntax:
long invert_rect(long left, long top, long right, long bottom)
Inversion is typically defined as taking the complement of each color component. For example:
color.red = 255 - color.red; color.green = 255 - color.green; color.blue = 255 - color.blue;
The inversion rectangle includes the pixel columns and rows that four arguments designate.
Graphics card drivers are not linked against the Application Server, so the Server cannot export functions to them. They are also not linked against any library. Consequently, they're generally limited to calling functions that they implement themselves.
However, in the current release, a graphics card driver can be statically linked against scalls.o, located with the libraries in /develop/libraries. < A future release will replace this file with a private library. >
Linking against scalls.o makes it possible for the driver to call any system function. The future library won't be as liberal, however, so system calls should be limited to the following functions:
Functions defined in the Kernel Kit |
---|
create_sem() |
acquire_sem() |
release_sem() |
delete_sem() |
system_time() |
snooze() |
spawn_thread() |
resume_thread() |
Functions defined in the Support Kit |
---|
atomic_add() |
Other functions |
---|
dprintf() < accessed through the name _kdprintf_() > |
set_dprintf_enabled() < accessed through the name _kset_dprintf_enabled_() > |
Functions from the first two groups are documented in the respective chapters on the Kernel Kit and the Support Kit. Functions in the last group are documented in the section on Functions for Drivers in this chapter on page 55.
The graphics card driver should be compiled as an "add-on image," as described in The Kernel Kit chapter. This means following the directions for compiling a shared library presented in the Metrowerks CodeWarrior manual. In summary, you'll need to specify the following options for the linker (as LDFLAGS in the makefile ):
#pragma export on long control_graphics_card(ulong op, void *data) { . . . } #pragma export off
and inform the linker with an -export pragma flag.
After the driver has been compiled, it should be installed in:
/system/addons/app_server
This is the only place where the Application Server will look for graphics card drivers to load.
The Server first looks for a driver for the graphics card in an app_server directory on a floppy disk (/fd/system/add-ons/app_server). Failing to find one, it looks next on the boot disk (/boot/system/add-ons/app_server).
When it searches each disk for a driver, the Application Server begins by looking for one developed specifically for the installed graphics card. If there are more than one, it's indeterminate which one it will choose to load. If there aren't any, the Server looks for the generic driver called supervga. This driver should be able to do a minimal job of putting a display on-screen, but probably won't be able to exploit the full potential of the graphics card.
You can give your driver any name you wish. However, the name "supervga" is reserved for the generic driver provided by Be.
The Be Book, HTML Edition, for Developer Release 8 of the Be Operating System.
Copyright © 1996 Be, Inc. All rights reserved.
Be, the Be logo, BeBox, BeOS, BeWare, and GeekPort are trademarks of Be, Inc.
Last modified September 6, 1996.