Render Buffers

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).

startframe / 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

selectrenderbuffer / executerenderbuffer / flushframe

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

Using a single render buffer

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.

executedlist

Instead of d2_executerenderbuffer a given Dlist can be executed directly by d2_executedlist.

Summary
Render BuffersRenderbuffers (similar in concept to OpenGL display lists) are the main interface between driver and hardware.
Renderbuffer Management
d2_newrenderbufferCreate a new renderbuffer.
d2_freerenderbufferDestroy and free a renderbuffer.
d2_selectrenderbufferChoose a renderbuffer for writing.
d2_executerenderbufferRender the content of a renderbuffer.
d2_getrenderbufferReturn internal renderbuffers.
Utility Functions
d2_startframeMark the begin of a scene.
d2_endframeMark the end of a scene.
d2_relocateframeChange framebuffer for render commands already issued.
d2_dumprenderbufferCopy the content of a renderbuffer into user memory.
d2_getrenderbuffersizeQuery the number of allocated display list entries.
d2_freedumpedbufferfree a chunk of memory returned from d2_dumprenderbuffer.

Renderbuffer Management

d2_newrenderbuffer

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.

parameters

handledevice pointer (see: d2_opendevice)
initialsizenumber of displaylist entries in the first page (minimum is 3)
stepsizenumber of displaylist entries in following pages (minimum is 3)

returns

pointer to internal renderbuffer (or NULL if failed)

see also

d2_getrenderbuffer, d2_setdlistblocksize, d2_freerenderbuffer

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.

note

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).

parameters

handledevice pointer (see: d2_opendevice)
bufferrenderbuffer address

returns

errorcode (D2_OK if successfull) see list of Errorcodes for details

d2_selectrenderbuffer

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).

parameters

handledevice pointer (see: d2_opendevice)
bufferrenderbuffer address or 0

returns

errorcode (D2_OK if successful) see list of Errorcodes for details

d2_executerenderbuffer

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.

parameters

handledevice pointer (see: d2_opendevice)
bufferrenderbuffer address
flags(not used)

returns

errorcode (D2_OK if successful) see list of Errorcodes for details

d2_getrenderbuffer

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.

parameters

handledevice pointer (see: d2_opendevice)
indexrenderbuffer index (only 0 and 1 are valid indices)

returns

pointer to internal renderbuffer (or NULL if failed)

Utility Functions

d2_startframe

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.

parameters

handledevice pointer (see: d2_opendevice)

returns

errorcode (D2_OK if successfull) see list of Errorcodes for details

d2_endframe

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.

parameters

handledevice pointer (see: d2_opendevice)

returns

errorcode (D2_OK if successfull) see list of Errorcodes for details

d2_relocateframe

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.

parameters

handledevice pointer (see: d2_opendevice)
ptrnew address of the top left pixel (coordinate 0,0)

returns

errorcode (D2_OK if successfull) see list of Errorcodes for details

note

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)!

note

If d2_adddlist (d2_al_no_copy) commands have been used these added dlists are not changed.

d2_dumprenderbuffer

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).

note

Use d2_layermerge to take care about outline and solid parts.

note

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.

parameters

handledevice pointer (see: d2_opendevice)
bufferrenderbuffer address
rdatapointer to memory (filled by function)
rsizesize of memory in bytes (filled by function)

returns

errorcode (D2_OK if successful) see list of Errorcodes for details

d2_getrenderbuffersize

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).

note

If d2_adddlist (d2_al_no_copy) commands have been used these added dlists are not counted.

parameters

handledevice pointer (see: d2_opendevice)
rbpointer to renderbuffer

returns

the number of allocated display list entries, or 0 if an error occurs

d2_freedumpedbuffer

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.

parameters

handledevice pointer (see: d2_opendevice)
datapointer to memory (created by d2_dumprenderbuffer)

returns

errorcode (D2_OK if successfull) see list of Errorcodes for details

d2_renderbuffer * d2_newrenderbuffer(d2_device *handle,
d2_u32 initialsize,
d2_u32 stepsize)
Create a new renderbuffer.
d2_s32 d2_freerenderbuffer(d2_device *handle,
d2_renderbuffer *buffer)
Destroy and free a renderbuffer.
d2_s32 d2_selectrenderbuffer(d2_device *handle,
d2_renderbuffer *buffer)
Choose a renderbuffer for writing.
d2_s32 d2_executerenderbuffer(d2_device *handle,
d2_renderbuffer *buffer,
d2_u32 flags)
Render the content of a renderbuffer.
d2_renderbuffer * d2_getrenderbuffer(d2_device *handle,
d2_s32 index)
Return internal renderbuffers.
d2_s32 d2_startframe(d2_device *handle)
Mark the begin of a scene.
d2_s32 d2_endframe(d2_device *handle)
Mark the end of a scene.
extern d2_s32 d2_relocateframe(d2_device *handle,
const void *ptr)
Change framebuffer for render commands already issued.
d2_s32 d2_dumprenderbuffer(d2_device *handle,
d2_renderbuffer *buffer,
void **rdata,
d2_s32 *rsize)
Copy the content of a renderbuffer into user memory.
d2_u32 d2_getrenderbuffersize(d2_device *handle,
d2_renderbuffer *rb)
Query the number of allocated display list entries.
d2_s32 d2_freedumpedbuffer(d2_device *handle,
void *data)
free a chunk of memory returned from d2_dumprenderbuffer.
d2_s32 d2_flushframe(d2_device *handle)
Wait for current rendering to end.
d2_s32 d2_executedlist(d2_device *handle,
const void *address,
d2_u32 flags)
Execute an already prepared display list.
d2_u32 d2_getdlistblockcount(d2_device *handle)
Get number of blocks of default displaylist (writelist).
d2_device * d2_opendevice(d2_u32 flags)
Create a new device handle.
d2_s32 d2_setdlistblocksize(d2_device *handle,
d2_u32 size)
Set blocksize for default displaylists.
List of all dave driver errorcodes.
There is a rendering function for each supported geometric shape.
Renderbuffers (similar in concept to OpenGL display lists) are the main interface between driver and hardware.
d2_s32 d2_selectrendermode(d2_device *handle,
d2_u32 mode)
Select a rendering mode.
d2_s32 d2_framebuffer(d2_device *handle,
void *ptr,
d2_s32 pitch,
d2_u32 width,
d2_u32 height,
d2_s32 format)
Specify the rendering target.
d2_s32 d2_layermerge(d2_device *handle)
Join outline and solid parts of currently selected renderbuffer.
d2_s32 d2_lowlocalmemmode(d2_device *handle,
d2_u32 dlistblockfactor,
d2_u32 dlistblocks)
Enable and configure the ‘low localmem’ mode.
d2_s32 d2_adddlist(d2_device *handle,
void *address,
d2_s32 size,
d2_u32 flags)
Add an already prepared display list to the current render buffer.
Close