Renderbuffers (similar in concept to OpenGL display lists) are the main interface between driver and hardware.
Issuing rendering commands to the D/AVE driver does not directly trigger a hardware activity but adds a set of commands to the currently selected Renderbuffer (see: d2_selectrenderbuffer).
This buffer can be executed directly by the hardware. For best performance and maximum parallelism there should always be one renderbuffer executing while another one is being filled (double-buffered render buffers).
The application can manage this on its own by using d2_selectrenderbuffer and d2_executerenderbuffer or make use of the utility functions and internal buffers (see: d2_startframe and d2_endframe).
The recommended method using double-buffered render buffers is to use d2_startframe and d2_endframe. These functions use two internal render buffers in turn. The internal render buffers can be accessed by d2_getrenderbuffer.
d2_startframe(handle); // --> start HW rendering of the previous frame (buffer a), switch to buffer b for all following render commands // ... now issue new render commands to buffer b while HW is rendering the previous frame from render buffer a ... d2_endframe(handle); // --> close render buffer b which has just captured all render commands, wait for HW to finish rendering of buffer a // may now propagate the rendered frame (from buffer a) to the display controller
Render buffers can also be managed by the application. Use d2_newrenderbuffer to allocate a new render buffer. To issue render commands a render buffer must be selected by d2_selectrenderbuffer. A render buffer can then be executed by d2_executerenderbuffer. Before d2_executerenderbuffer can be called again the application has to wait for Dave to be finished by d2_flushframe.
d2_selectrenderbuffer(handle, buffer); // issue render commands d2_executerenderbuffer(handle, buffer); d2_flushframe(handle); // propagate the rendered frame to the display controller
Please note that when using just a single render buffer (no double-buffering) the allocated buffer can not be freed as long as it is selected because the buffer will be linked for internal usage. This means that another call of d2_selectrenderbuffer must be issued with a second buffer to de-select the previous buffer to avoid memory leaks.
buffer = d2_newrenderbuffer(handle, 25, 25); d2_selectrenderbuffer(handle, buffer); d2_executerenderbuffer(handle, buffer, d2_ef_default); d2_flushframe(handle); ... // select a different buffer before freeing d2_selectrenderbuffer(handle, newbuffer); d2_freerenderbuffer(handle, buffer);
If no second render buffer is available and only a single render buffer should be used the following two commands have to be called before creating any render buffer. This will prevent internal buffer linkage!
// close internal render buffer 0 d2_executerenderbuffer(locD2DHandle,d2_getrenderbuffer(locD2DHandle, 0), 0); // close internal render buffer 1 d2_executerenderbuffer(locD2DHandle,d2_getrenderbuffer(locD2DHandle, 1), 0); ... buffer = d2_newrenderbuffer(handle, 25, 25); d2_selectrenderbuffer(handle, buffer); d2_executerenderbuffer(handle, buffer, d2_ef_default); d2_flushframe(handle); d2_freerenderbuffer(handle, buffer); // free a selected buffer
However, it is recommended to use at least two render buffers, e.g. d2_startframe and d2_endframe.
Instead of d2_executerenderbuffer a given Dlist can be executed directly by d2_executedlist.
Render Buffers | Renderbuffers (similar in concept to OpenGL display lists) are the main interface between driver and hardware. |
Renderbuffer Management | |
d2_newrenderbuffer | Create a new renderbuffer. |
d2_freerenderbuffer | Destroy and free a renderbuffer. |
d2_selectrenderbuffer | Choose a renderbuffer for writing. |
d2_executerenderbuffer | Render the content of a renderbuffer. |
d2_getrenderbuffer | Return internal renderbuffers. |
Utility Functions | |
d2_startframe | Mark the begin of a scene. |
d2_endframe | Mark the end of a scene. |
d2_relocateframe | Change framebuffer for render commands already issued. |
d2_dumprenderbuffer | Copy the content of a renderbuffer into user memory. |
d2_getrenderbuffersize | Query the number of allocated display list entries. |
d2_freedumpedbuffer | free a chunk of memory returned from d2_dumprenderbuffer. |
d2_renderbuffer * d2_newrenderbuffer( d2_device * handle, d2_u32 initialsize, d2_u32 stepsize )
Create a new renderbuffer.
Renderbuffers are filled by the driver but read (executed) directly by the Dave hardware. Buffers grow on demand but only shrink slowly: If a page was not used for 60 calls of d2_executerenderbuffer, the page is freed one at a time: The next page will not be freed before 60 further calls have elapsed.
A single displaylist entry requires 20bytes of memory, choosing large page sizes is potential waste of memory while too many small pages can degrade the performance of both reading and writing to the buffer.
By using d2_getrenderbuffersize, it is possible to query the number of used entries for a given application. This can be used to optimize the page size.
The number of used pages of the renderbuffer currently used as writebuffer can be queried using d2_getdlistblockcount.
handle | device pointer (see: d2_opendevice) |
initialsize | number of displaylist entries in the first page (minimum is 3) |
stepsize | number of displaylist entries in following pages (minimum is 3) |
pointer to internal renderbuffer (or NULL if failed)
d2_getrenderbuffer, d2_setdlistblocksize, d2_freerenderbuffer
d2_s32 d2_freerenderbuffer( d2_device * handle, d2_renderbuffer * buffer )
Destroy and free a renderbuffer.
You can only free buffers that were created by d2_newrenderbuffer and are not currently executed. To make sure execution has finished the application can call d2_flushframe.
Please note that when using just a single render buffer (no double buffering) the allocated buffer can not be freed as long as it is selected (see above for more details).
handle | device pointer (see: d2_opendevice) |
buffer | renderbuffer address |
errorcode (D2_OK if successfull) see list of Errorcodes for details
d2_s32 d2_selectrenderbuffer( d2_device * handle, d2_renderbuffer * buffer )
Choose a renderbuffer for writing. Selecting a buffer that is currently executed will cause rendering failures.
The previously selected renderbuffer is flushed. All subsequent Rendering Functions write to the specified renderbuffer. The buffer is finalized when d2_executerenderbuffer is called. The render buffer is reset for writing a new list after selection.
For the usage of render buffers see Render Buffers.
If buffer is 0 then the internal renderbuffer for writing will be selected, thus d2_startframe/d2_endframe can be continued to use (see also d2_getrenderbuffer).
handle | device pointer (see: d2_opendevice) |
buffer | renderbuffer address or 0 |
errorcode (D2_OK if successful) see list of Errorcodes for details
d2_s32 d2_executerenderbuffer( d2_device * handle, d2_renderbuffer * buffer, d2_u32 flags )
Render the content of a renderbuffer.
For the usage of render buffers see Render Buffers.
Before rendering is started, the renderbuffer is prepared for execution. This involves flushing of scratch buffers, possibly merge of layers in certain render modes (see d2_selectrendermode) and potentially copying the display list to a dedicated video memory or at least flushing of the CPU data caches. The buffer passed to d2_executerenderbuffer can be used for execution again by calling d2_executerenderbuffer again with the same buffer as argument. But before new render commands can be written to the buffer it must be selected by d2_selectrenderbuffer.
Note that before calling d2_executerenderbuffer, it must be made sure that no render buffer is currently executed on the hardware. This can be done by either waiting for the respective interrupt or by calling d2_flushframe.
Note that even when d2_flushframe is issued to wait for the rendering of the buffer to finish the buffer still has to be reselected (using d2_selectrenderbuffer) in order to use it again for rendering.
Note that calling this function from inside an interrupt service routine is not recommended, as the execution time can not be foreseen. If it is called from inside the D/AVE ‘display list finished’ ISR anyway, it needs to be made sure that clearing the IRQ happens before the call to d2_executerenderbuffer! Register writes to the D/AVE core are not allowed while a display list is being executed.
Note that if d2_ef_execute_once is used a new render buffer must be selected by d2_selectrenderbuffer even if it is the same render buffer.
handle | device pointer (see: d2_opendevice) |
buffer | renderbuffer address |
flags | (not used) |
errorcode (D2_OK if successful) see list of Errorcodes for details
d2_renderbuffer * d2_getrenderbuffer( d2_device * handle, d2_s32 index )
Return internal renderbuffers.
Two renderbuffers are allocated automatically for every device. These cannot be freed manually (destruction is automatic) but can be used for rendering.
Note that if internal buffers are used the utility functions d2_startframe and d2_endframe might not work as expected anymore. These functions use both internal buffers for ‘double buffering’ and rely on using d2_selectrenderbuffer exclusively.
handle | device pointer (see: d2_opendevice) |
index | renderbuffer index (only 0 and 1 are valid indices) |
pointer to internal renderbuffer (or NULL if failed)
d2_s32 d2_startframe( d2_device * handle )
Mark the begin of a scene.
Use this function (together with d2_endframe) to let the driver handle render buffer execution and flipping automatically.
When startframe is called the render buffer that was filled during the last frame (between previous d2_startframe/d2_endframe) is executed on the HW. New render commands that are sent after this ‘startframe’ are put into the other render buffer.
For the usage of render buffers see Render Buffers.
handle | device pointer (see: d2_opendevice) |
errorcode (D2_OK if successfull) see list of Errorcodes for details
d2_s32 d2_endframe( d2_device * handle )
Mark the end of a scene.
Use this function (together with d2_startframe) to let the driver handle render buffer execution and flipping automatically.
Endframe makes sure the previous frame (the one started on the HW by the last call of d2_startframe) has been rendered completely. A wait for the HW is done if necessary. The render buffer just filled with render commands (since the last d2_startframe) is logically closed.
For the usage of render buffers see Render Buffers.
handle | device pointer (see: d2_opendevice) |
errorcode (D2_OK if successfull) see list of Errorcodes for details
extern d2_s32 d2_relocateframe( d2_device * handle, const void * ptr )
Change framebuffer for render commands already issued.
This function can be used to change the target framebuffer of all d2 render commands that have been issued since the last d2_startframe.
It does only work if framebuffer format and size stay the same and only a single framebuffer has been set used d2_framebuffer since the frame has been started. The current framebuffer is not changed, this would require a call to d2_framebuffer afterwards.
handle | device pointer (see: d2_opendevice) |
ptr | new address of the top left pixel (coordinate 0,0) |
errorcode (D2_OK if successfull) see list of Errorcodes for details
Intention of this function is to support an immediate flush to a hidden framebuffer when the frame currently assembled was initially prepared for the currently displayed framebuffer. Use d2_layermerge to take care about outline and solid parts.
This function can only be used when double word clearing is disabled (see: d2_opendevice) and ‘low localmem’ mode is not enabled (see: d2_lowlocalmemmode)!
If d2_adddlist (d2_al_no_copy) commands have been used these added dlists are not changed.
d2_s32 d2_dumprenderbuffer( d2_device * handle, d2_renderbuffer * buffer, void ** rdata, d2_s32 * rsize )
Copy the content of a renderbuffer into user memory.
The entire renderbuffer is stored as one flat dave displaylist in memory. Writes to the displaylist control register (display list jumps) are removed and replaced by the code following at the new address - this way the dumped list can be relocated in memory.
Note that the application has to free the memory allocated for a dumped list using d2_freedumpedbuffer.
This function can only be used when double word clearing is disabled (see: d2_opendevice) and ‘low localmem’ mode is not enabled (see: d2_lowlocalmemmode).
Use d2_layermerge to take care about outline and solid parts.
d2_dumprenderbuffer does not work correctly if d2_adddlist (d2_al_no_copy) commands have been used. Use d2_adddlist (d2_al_copy) instead if you want to get dlists with the desired content.
handle | device pointer (see: d2_opendevice) |
buffer | renderbuffer address |
rdata | pointer to memory (filled by function) |
rsize | size of memory in bytes (filled by function) |
errorcode (D2_OK if successful) see list of Errorcodes for details
d2_u32 d2_getrenderbuffersize( d2_device * handle, d2_renderbuffer * rb )
Query the number of allocated display list entries. Each display list entry is based on one address word and 4 data words (20 bytes). This function can be used to profile an application and optimize the page sizes set via d2_setdlistblocksize or d2_newrenderbuffer. It is recommended to call this function only directly before d2_executerenderbuffer, when all required commands are inside the render buffer.
This function can only be used when ‘low localmem’ mode is not enabled (see: d2_lowlocalmemmode).
If d2_adddlist (d2_al_no_copy) commands have been used these added dlists are not counted.
handle | device pointer (see: d2_opendevice) |
rb | pointer to renderbuffer |
the number of allocated display list entries, or 0 if an error occurs
d2_s32 d2_freedumpedbuffer( d2_device * handle, void * data )
free a chunk of memory returned from d2_dumprenderbuffer.
Dumped renderbuffers must be released using this function. Passing a NULL pointer for ‘data’ is accepted and does nothing.
handle | device pointer (see: d2_opendevice) |
data | pointer to memory (created by d2_dumprenderbuffer) |
errorcode (D2_OK if successfull) see list of Errorcodes for details
Create a new renderbuffer.
d2_renderbuffer * d2_newrenderbuffer( d2_device * handle, d2_u32 initialsize, d2_u32 stepsize )
Destroy and free a renderbuffer.
d2_s32 d2_freerenderbuffer( d2_device * handle, d2_renderbuffer * buffer )
Choose a renderbuffer for writing.
d2_s32 d2_selectrenderbuffer( d2_device * handle, d2_renderbuffer * buffer )
Render the content of a renderbuffer.
d2_s32 d2_executerenderbuffer( d2_device * handle, d2_renderbuffer * buffer, d2_u32 flags )
Return internal renderbuffers.
d2_renderbuffer * d2_getrenderbuffer( d2_device * handle, d2_s32 index )
Mark the begin of a scene.
d2_s32 d2_startframe( d2_device * handle )
Mark the end of a scene.
d2_s32 d2_endframe( d2_device * handle )
Change framebuffer for render commands already issued.
extern d2_s32 d2_relocateframe( d2_device * handle, const void * ptr )
Copy the content of a renderbuffer into user memory.
d2_s32 d2_dumprenderbuffer( d2_device * handle, d2_renderbuffer * buffer, void ** rdata, d2_s32 * rsize )
Query the number of allocated display list entries.
d2_u32 d2_getrenderbuffersize( d2_device * handle, d2_renderbuffer * rb )
free a chunk of memory returned from d2_dumprenderbuffer.
d2_s32 d2_freedumpedbuffer( d2_device * handle, void * data )
Wait for current rendering to end.
d2_s32 d2_flushframe( d2_device * handle )
Execute an already prepared display list.
d2_s32 d2_executedlist( d2_device * handle, const void * address, d2_u32 flags )
Get number of blocks of default displaylist (writelist).
d2_u32 d2_getdlistblockcount( d2_device * handle )
Create a new device handle.
d2_device * d2_opendevice( d2_u32 flags )
Set blocksize for default displaylists.
d2_s32 d2_setdlistblocksize( d2_device * handle, d2_u32 size )
Select a rendering mode.
d2_s32 d2_selectrendermode( d2_device * handle, d2_u32 mode )
Specify the rendering target.
d2_s32 d2_framebuffer( d2_device * handle, void * ptr, d2_s32 pitch, d2_u32 width, d2_u32 height, d2_s32 format )
Join outline and solid parts of currently selected renderbuffer.
d2_s32 d2_layermerge( d2_device * handle )
Enable and configure the ‘low localmem’ mode.
d2_s32 d2_lowlocalmemmode( d2_device * handle, d2_u32 dlistblockfactor, d2_u32 dlistblocks )
Add an already prepared display list to the current render buffer.
d2_s32 d2_adddlist( d2_device * handle, void * address, d2_s32 size, d2_u32 flags )