pfCycleBuffer OBSOLETE(3pf) OpenGL Performer 3.2.2 libpr C Reference Pages
NAME
pfNewCBuffer, pfGetCBufferClassType, pfGetCurCBufferData,
pfGetCBufferCMem, pfCBufferChanged, pfInitCBuffer, pfCBufferConfig,
pfGetCBufferConfig, pfCBufferFrame, pfGetCBufferFrameCount,
pfGetCurCBufferIndex, pfCurCBufferIndex, pfGetCBuffer, pfGetCMemFrame,
pfGetCMemCBuffer, pfGetCMemClassType - pfCycleBuffer and pfCycleMemory
obsoleted by pfFlux and pfFluxMemory
FUNCTION SPECIFICATION
#include <Performer/pr.h>
pfCycleBuffer * pfNewCBuffer(size_t nbytes, void *arena);
pfType * pfGetCBufferClassType(void);
void * pfGetCurCBufferData(const pfCycleBuffer *cbuf);
pfCycleMemory * pfGetCBufferCMem(const pfCycleBuffer *cbuf, int index);
void pfCBufferChanged(pfCycleBuffer *cbuf);
void pfInitCBuffer(pfCycleBuffer *cbuf, void *data);
int pfCBufferConfig(int numBuffers);
int pfGetCBufferConfig(void);
int pfCBufferFrame(void);
int pfGetCBufferFrameCount(void);
int pfGetCurCBufferIndex(void);
void pfCurCBufferIndex(int index);
pfCycleBuffer * pfGetCBuffer(void *data);
int pfGetCMemFrame(const pfCycleMemory *cmem);
pfCycleBuffer * pfGetCMemCBuffer(pfCycleMemory *cmem);
pfType * pfGetCMemClassType(void);
PARENT CLASS FUNCTIONS
The OpenGL Performer class pfCycleBuffer is derived from the parent class
pfObject, so each of these member functions of class pfObject are also
directly usable with objects of class pfCycleBuffer. Casting an object
of class pfCycleBuffer to an object of class pfObject is taken care of
automatically. This is also true for casts to objects of ancestor
classes of class pfObject.
Page 1
pfCycleBuffer OBSOLETE(3pf) OpenGL Performer 3.2.2 libpr C Reference Pages
void pfUserDataSlot(pfObject *obj, int slot, void *data);
void pfUserData(pfObject *obj, void *data);
void* pfGetUserDataSlot(pfObject *obj, int slot);
void* pfGetUserData(pfObject *obj);
int pfGetNumUserData(pfObject *obj);
int pfGetNamedUserDataSlot(const char *name);
const char* pfGetUserDataSlotName(int slot);
int pfGetNumNamedUserDataSlots(void);
int pfGetGLHandle(pfObject *obj);
int pfDeleteGLHandle(pfObject *obj);
Since the class pfObject is itself derived from the parent class
pfMemory, objects of class pfCycleBuffer can also be used with these
functions designed for objects of class pfMemory.
pfType * pfGetType(const void *ptr);
int pfIsOfType(const void *ptr, pfType *type);
int pfIsExactType(const void *ptr, pfType *type);
const char * pfGetTypeName(const void *ptr);
int pfRef(void *ptr);
int pfUnref(void *ptr);
int pfUnrefDelete(void *ptr);
int pfUnrefGetRef(void *ptr);
int pfGetRef(const void *ptr);
int pfCopy(void *dst, void *src);
int pfDelete(void *ptr);
int pfIsFluxed(void *ptr);
int pfCompare(const void *ptr1, const void *ptr2);
void pfPrint(const void *ptr, uint which, uint verbose,
FILE *file);
void * pfGetArena(void *ptr);
DESCRIPTION
Together, pfCycleBuffer and pfCycleMemory provide an automated mechanism
for managing dynamic data in a pipelined, multiprocessing environment.
In this kind of environment, data is typically modified at the head of
the pipeline and must propagate down it in a "frame-accurate" fashion.
For example, assume the coordinates of a pfGeoSet are modified for facial
animation. If a two-stage rendering pipeline is used, then it is likely
that the coordinates will be modified in the head of the pipeline, at the
same time they are being rendered in the tail of the pipeline. If only a
single memory buffer is used, then the pfGeoSet might be rendered when
its coordinates are only partially updated, potentially resulting in
cracks in the facial mesh or other anomalies.
A solution to this problem is to use two memory buffers for the
coordinates, one written to by the head and one read from by the tail of
the pipeline. In order for the new coordinates to propagate to the
rendering stage we could copy the newly updated buffer into the
renderer's buffer during a handshake period between the two stages.
However, if the buffer is large, the copy time could become
Page 2
pfCycleBuffer OBSOLETE(3pf) OpenGL Performer 3.2.2 libpr C Reference Pages
objectionable. Another alternative is to simply swap pointers to the two
buffers - the classic "double-buffering" approach. This is much more
efficient but requires that the contents of the buffer be completely
updated each frame. Otherwise the render stage will access a "stale"
buffer that represents the facial expression at a previous time so that
the animation will appear to go backwards.
The pfCycleBuffer/pfCycleMemory combination supports efficient dynamic
data management in an N-stage pipeline. A pfCycleBuffer logically
contains multiple pfCycleMemorys. Each process has a global index which
selects the currently active pfCycleMemory in each pfCycleBuffer. This
index can be advanced once a frame by pfCurCBufferIndex so that the
buffers "cycle". By advancing the index appropriately in each pipeline
stage, dynamic data can be frame-accurately propagated down the pipeline.
While pfCycleBuffers can be used for generic dynamic data, a prominent
use is as attribute arrays for pfGeoSets. pfGSetAttr accepts
pfCycleBuffer memory for attribute arrays and the pfGeoSet will index the
appropriate pfCycleMemory when rendering and intersection testing.
Currently, pfGeoSets do not support pfCycleBuffer index lists.
pfNewCBuffer returns a pfCycleBuffer allocated out of arena or off the
heap if arena is NULL. The argument nbytes specifies the length of each
associated pfCycleMemory. pfCycleBuffers can be deleted with pfDelete.
The number of pfCycleMemorys allocated for each pfCycleBuffer is
specified by pfCBufferConfig which is typically called only once at
initialization time. pfGetCBufferConfig returns the number set by
pfCBufferConfig.
pfGetCBufferClassType returns the pfType* for the class pfCycleBuffer.
The pfType* returned by pfGetCBufferClassType is the same as the pfType*
returned by invoking pfGetType on any instance of class pfCycleBuffer.
Because OpenGL Performer allows subclassing of built-in types, when
decisions are made based on the type of an object, it is usually better
to use pfIsOfType to test if an object is of a type derived from a
Performer type rather than to test for strict equality of the pfType*'s.
pfGetCMemClassType returns the pfType* for the class pfCycleMemory.
pfInitCBuffer initializes all pfCycleMemorys of cbuf to the data
referenced by data. data should be at least of size nbytes.
pfCycleMemory is derived from pfMemory and also provides access to its
raw data in the form of a void* pointer through the pfGetData call. Thus
pfCycleBuffer memory is arranged in a hierarchy: pfCycleBuffer ->
pfCycleMemory -> void* and various routines exist which convert one
handle into another. These routines are listed in the following table.
pfCycleBuffer* pfCycleMemory* void*
|
|
|
Page 3
pfCycleBuffer OBSOLETE(3pf) OpenGL Performer 3.2.2 libpr C Reference Pages
___________________________________________________________________________
pfCycleBuffer* NA pfGetCBufferCMem pfGetCurCBufferData
pfCycleMemory* pfGetCMemCBuffer NA pfGetData
void* pfGetCBuffer pfGetMemory NA
|
|
|
The currently active pfCycleMemory portion of a pfCycleBuffer is selected
by the global index specified by pfCurCBufferIndex, and is returned by
pfGetCurCBufferIndex. One can think of this in pseudocode as
current pfCycleMemory = pfCycleBuffer[pfCurCBufferIndex]
Thus one should always get a new handle to the currently active data
whenever the global index changes. Data modification that is incremental,
(such as a += .2) must retain a handle to the previous data for proper
results (current a = previous a + .2).
As mentioned above, cycling buffer pointers is efficient but requires
that the buffers be completely updated each frame. If the data at some
time becomes static, it must then be copied into those buffers that are
out of date. pfCycleBuffer supports this copying automatically with
pfCBufferChanged in conjunction with pfCBufferFrame. pfCBufferFrame
advances a global frame counter that is used to frame-stamp
pfCycleMemorys. After cbuf has been updated, pfCBufferChanged frame-
stamps cbuf with the current frame count. Then if cbuf is not changed in
a later frame, pfCBufferFrame will automatically copy the latest
pfCycleMemory into its currently active, sibling pfCycleMemory. This
copying will continue until all selected pfCycleMemorys contain the
latest data. pfGetCMemFrame returns the frame stamp of cmem.
pfGetCBufferFrameCount returns the current, global, pfCycleBuffer frame
count.
The following are examples of pfCycleBuffer usage for libpr-only and
libpf applications. When using libpf, pfConfig and pfFrame call
pfCBufferConfig and pfCBufferFrame respectively so the application should
not call the latter routines. In addition, libpf calls pfCurCBufferIndex
in each process so that pfCycleBuffer changes are properly propagated
down the processing pipelines.
Example 1: libpr-only pfCycleBuffer example
pfVec3 *prevVerts, *curVerts;
/*
* Configure number of pfCycleMemorys per pfCycleBuffer
*/
pfCBufferConfig(numBuffers);
verts = pfNewCBuffer(sizeof(pfVec3) * numVerts, arena);
pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, NULL);
Page 4
pfCycleBuffer OBSOLETE(3pf) OpenGL Performer 3.2.2 libpr C Reference Pages
while(!done)
{
static int index = 0;
pfCurCBufferIndex(index);
curVerts = pfGetCurCBufferData(verts);
/* Compute new positions of mass-spring system */
for (i=0; i<numVerts; i++)
curVerts[i] = prevVerts[i] + netForceVector * deltaTime;
/* Indicate that 'verts' has changed */
pfCBufferChanged(verts);
prevVerts = curVerts;
/* Advance cyclebuffer frame count */
pfCBufferFrame();
/* Advance buffer index. */
index = (index + 1) % numBuffers;
}
Example 2: libpf pfCycleBuffer example
pfVec3 *prevVerts, *curVerts;
pfInit();
pfMultiprocess(mpMode);
/*
* This calls pfCBufferConfig() with the number of buffers
* appropriate to the multiprocessing mode.
*/
pfConfig();
verts = pfNewCBuffer(sizeof(pfVec3) * numVerts, pfGetSharedArena());
pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, NULL);
while(!done)
{
curVerts = pfGetCurCBufferData(verts);
/* Compute new positions of mass-spring system */
for (i=0; i<numVerts; i++)
curVerts[i] = prevVerts[i] + netForceVector * deltaTime;
Page 5
pfCycleBuffer OBSOLETE(3pf) OpenGL Performer 3.2.2 libpr C Reference Pages
/* Indicate that 'verts' has changed */
pfCBufferChanged(verts);
prevVerts = curVerts;
/* This calls pfCBufferFrame() */
pfFrame();
}
NOTES
The global index which selects the currently active pfCycleMemory is
unique for a given address space. Specifically, share group processes
like those spawned by sproc will share the same global index.
OBSOLETE
pfCycleBuffer and pfCycleMemory have been obsoleted by pfFlux and
pfFluxMemory. See the pfFlux man page for examples on converting code
using pfCycleBuffer to pfFluxBuffer.
SEE ALSO
pfFlux, pfDelete, pfGetData, pfGetMemory, pfMemory
Page 6