Table of miscellaneous drawing functions
#include <draw.h> typedef struct disp_draw_miscfuncs { int (*init) (…); void (*fini) (…); void (*module_info) (…); int (*set_palette) (…); void (*flushrect) (…); void (*get_2d_caps) (…); int (*get_corefuncs_sw) (…); int (*get_contextfuncs_sw) (…); int (*end_of_draw) (…); int (*attach_external) (…); int (*detach_external) (…); int (*recover) (…); int (*wait_idle) (…); } disp_draw_miscfuncs_t;
The disp_draw_miscfuncs_t structure is a table that your driver uses to define the miscellaneous drawing functions that it provides to the graphics framework. Your driver's devg_get_miscfuncs() entry point must fill in this structure.
The graphics framework calls this function to initialize the drawing hardware, allocate resources, and so on. The prototype is:
int (*init) (disp_adapter_t *adapter, char *optstring )
For more information on where this function fits into the general flow, see “Calling sequence” in the Writing a Graphics Driver chapter.
The graphics framework calls this function to shut down the driver by shutting off hardware, freeing resources, and so on. The prototype is:
void (*fini) (disp_adapter_t *adapter)
For more information on where this function fits into the general flow, see “Calling sequence” in the Writing a Graphics Driver chapter.
The graphics framework calls this function to get information about the 2D driver module. The prototype is:
void (*module_info) ( disp_adapter_t *adapter, disp_module_info_t *module_info)
This function must fill in the disp_module_info_t structure pointed to by module_info.
The graphics framework calls this function to set the palette. The prototype is:
int (*set_palette) (disp_adapter_t *ctx, int index, int count, disp_color_t *pal)
If the modeswitcher version of this function (disp_modefuncs->set_palette) is present, it's called instead (i.e. the modeswitcher function overrides this one). |
The graphics framework calls this function to flush a modified area to the draw surface. The prototype is:
void (*flushrect) (disp_draw_context_t *ctx, int x1, int y1, int x2, int y2)
The area defined by (x1, y1), (x2, y2) has been modified. Higher level software keeps track of which parts of the screen have been modified (or “dirtied”), since the last call to this function, and this function is called to flush the dirtied area to the targeted draw surface.
This function is optional; supply it only if you wish to implement a “dirty rectangle” driver. The sample VGA driver provided with the DDK is a good example of a dirty rectangle driver.
Even though the frame buffer organization is non-linear, the VGA driver is still able to use the standard rendering functions from the FFB lib. It does this by keeping a “shadow” copy of the frame buffer in system RAM. The format of the shadow buffer is linear (8-bit palette format). The FFB renders into the shadow buffer, then this function is used to flush the appropriate area of the shadow buffer out to the planar VGA frame buffer, by converting the data from linear to planar format.
The graphics framework calls this function to get information about the 2D capabilities of the graphics hardware's accelerator. The prototype is:
void (*get_2d_caps) (disp_adapter_t *ctx, disp_surface_t *surface, disp_2d_caps_t *caps)
The surface argument points to a disp_surface_t structure that describes a targetable 2D surface. Your driver must fill in the disp_2d_caps_t structure pointed to by caps with information about how 2D drawing to that surface is to be performed.
The graphics framework calls this function to get your driver's core 2D drawing functions. The prototype is:
int (*get_corefuncs_sw)( disp_adapter_t *adapter, unsigned pixel_format, disp_draw_corefuncs_t *fns, int tabsize );
This function should be similar to devg_get_corefuncs(), but get_corefuncs_sw() should get only the ones that are guaranteed to render into system RAM.
The graphics framework calls this function to get your driver's context 2D drawing functions. The prototype is:
int (*get_contextfuncs_sw)( disp_adapter_t *adapter, disp_draw_contextfuncs_t *fns, int tabsize );
This function should be similar to devg_get_contextfuncs(), but get_contextfuncs_sw() should get only the ones that are guaranteed to render into system RAM.
The graphics framework calls this function to initiate rendering of any outstanding 2D draw commands.
This function is optional; it may need to be provided by your driver depending on the nature of the hardware. Many devices queue draw commands in a draw list, or ring buffer. The driver then initiates processing, at which point the buffer contents are transferred to the hardware, which causes the hardware to actually process the commands and render. For efficiency, most of the driver's rendering entry points do not initiate any rendering, but simply place instructions in a command buffer.
When this entry point (end_of_draw()) is called, the driver should ensure that it initiates processing of any outstanding command buffers. This function does not need to wait for the processing to be completed, it merely needs to ensure that all outstanding draw commands that have been issued will complete in a finite period of time without further calls into the driver.
The prototype is:
int (*end_of_draw)(disp_adapter_t *adapter);
The graphics framework calls this function to prepare the driver so that other rendering entry points can be called from a client's address space.
The prototype is:
int (*attach_external) (disp_adapter_t *adapter, disp_aperture_t aper[]);
When a client application wishes to render, it first registers with the display server. If this is the first application to attach, the server will call the driver's initialization sequence. This initialization sequence takes place within the address space of the display server. Once the client has registered successfully, it may then begin calling into the driver directly from within its own address space. However, this function will always be the first to be called from within the address space of a newly registered client.
The driver must use this entry-point to prepare itself so that other rendering entry points may be called from the client's address space. Be very careful when using pointers within the driver's rendering entry points. Note that any pointer only has meaning within a single address space. De-referencing a pointer that was created within the address space of another client, or within the address space of the display server, will have catastrophic results.
Each time this entry point is called, it is passed a pointer to a new copy of the disp_adapter_t structure. Only the following members of the disp_adapter_t are initialized upon entry:
The driver is responsible for initializing the caps field of the disp_adapter_t, as well as for storing any driver-private handles that it may need during rendering.
The shmem member of the disp_adapter_t points to the global device state structure, which resides in shared memory. This is the structure that the driver initialized in the modefuncs->init() entry point.
The aper argument points to an array of pointers to any memory apertures that were declared by your memory-manager's query_apertures() entry point, which is mapped into the client's address space. Since the client may not be running with super-user privileges, the driver should access its memory-mapped registers via these pointers, instead of attempting to map physical memory.
The graphics framework calls this function when a client no longer wishes to call the driver's rendering entry points. This function should free any resources that were allocated by the attach_external() entry point.
The prototype is:
int (*detach_external) (disp_adapter_t *adapter);
The graphics framework calls this function when it detects that a client has terminated while it had the hardware locked.
The prototype is:
int (*recover) (disp_adapter_t *adapter);
It is possible that a client could be terminated at any time, even while it is in the middle of calling one of the driver's entry points. Consider the ramifications this could have on your driver. For example, the driver could have been in the middle of building a command packet to send to the device. When another client tries to render, there could be a corrupt or partially-complete command packet in the command buffer, which could lock up the device.
Fortunately, there is a mechanism in the display server to detect the case where a client terminates while it has locked the hardware for rendering. When the framework detects this condition, this entry point is called. This entry point is responsible for putting the device into a consistent state, such that other clients will subsequently be able to render. Depending on the device, this could involve discarding some draw data, or even resetting the rendering engine.
The graphics framework calls this function to flush any outstanding rendering operations, and block until all rendering has been completed.
The prototype is:
int (*wait_idle) (disp_adapter_t *adapter);
This function is similar to the “core” wait_idle() entry point. However, this function is called from within the address space of the display server, as opposed to from within the client's address space.
Neutrino
devg_get_miscfuncs(), disp_2d_caps_t, disp_adapter_t, disp_modefuncs_t, disp_module_info_t, disp_surface_t,