Nicolas Gauvin (nicolas++at++cae.ca)
Tue, 13 Feb 1996 14:14:17 -0500
First pfBuffer::merge() seems to be very fragile. As reported
earlier, parents need to be created before their children otherwise
we end up with the infamous 'nb_clean' crash. This single constraint
can cause limitations in the design of an efficient paging system and
I wouldn't be surprised that some of the loaders that are shipped
with Performer 2.0 do not respect it.
However even when I created simple Performer nodes myself
in the correct order I still ended up with 'nb_clean' crashes much
like those reported by Scott Friedman.
I investigated a bit further and I have found that pfBuffer::merge()
will undoubtly crash if I have requested more than one bufferAddChild
before calling it. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The only workaround I have found for this is to call pfBuffer::merge()
after each and every bufferAddChild requests instead of using a single call
once all children have been created and added with various bufferAddChild.
Attached to this message is a version of simple.C that illustrates
the problem and workaround. The original simple.C with its Makefile is
found in /usr/share/Performer/src/pguide/libpf/C++
This workaround however has a cost associated to it as reported in
the pfBuffer man pages:
" pfBuffer::merge will adversely impact the APP process, "
" proportional to the number of pfBuffer::addChild and "
" pfBuffer::removeChild requests. "
In a realistic database paging system many tiles may need to be
suddenly paged in. If I have to call pfBuffer::merge for each of
them, performance of the APP process will degrade.
In my opinion these bugs are important enough to justify a fix.
Especially if we consider that previous beta versions of Performer
seemed to have a better working pfBuffer::merge.
I would be interested to know if there is a plan in that regard.
I know that distributing patches for a big product like Performer must
be a major pain especially with all those versions of the libraries but if
it's not done then we are stuck with a database paging system barely usable.
So far I have been really impressed and satisfied with the quality of
the Performer 2.0 release. However the bugs related to pfBuffer are
the first ones I have found that can really cause me problems.
--
___/ | ___/ Nicolas Gauvin e-mail: nicolas++at++cae.ca
/ / | / Software Developper voice: (514) 341-2000 x2275
/ / | __/ CAE Electronics Ltd. fax: (514) 340-5496
/ ___ | / 8585 Cote De Liesse, P.O. Box 1800
_____/ _/ _| _____/ Saint-Laurent, Quebec, Canada, H4L-4X4
//
// Copyright 1995, Silicon Graphics, Inc.
// ALL RIGHTS RESERVED
//
// UNPUBLISHED -- Rights reserved under the copyright laws of the United
// States. Use of a copyright notice is precautionary only and does not
// imply publication or disclosure.
//
// U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
// Use, duplication or disclosure by the Government is subject to restrictions
// as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
// in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
// in similar or successor clauses in the FAR, or the DOD or NASA FAR
// Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
// 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
//
// Permission to use, copy, modify, distribute, and sell this software
// and its documentation for any purpose is hereby granted without
// fee, provided that (i) the above copyright notices and this
// permission notice appear in all copies of the software and related
// documentation, and (ii) the name of Silicon Graphics may not be
// used in any advertising or publicity relating to the software
// without the specific, prior written permission of Silicon Graphics.
//
// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
// INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
// THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
// OR PERFORMANCE OF THIS SOFTWARE.
//
//
// simpleC.C: simple Performer program for programmer's guide
//
// $Revision: 1.10 $
// $Date: 1995/11/22 14:35:21 $
//
#include <stdlib.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfLightSource.h>
#include <Performer/pf/pfNode.h>
#include <Performer/pf/pfScene.h>
#include <Performer/pfutil.h>
#include <Performer/pfdu.h>
#include <Performer/pf.h>
#include <Performer/pf/pfBuffer.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfGeode.h>
#include <Performer/pr/pfGeoSet.h>
// DBase passdata stucture containing only the Performer scene
struct DBaseData {
pfScene* scene;
};
//
// Usage() -- print usage advice and exit. This
// procedure is executed in the application process.
//
static void
Usage (void)
{
pfNotify(PFNFY_FATAL, PFNFY_USAGE, "Usage: simpleC file.ext ...\n");
exit(1);
}
// Very simple DBase callback that alternatively
// pages in and out two simple Performer branches
// and illustrates the pfBuffer::merge problem
// as well as a workaround.
void DBaseFunc( void* _data )
{
DBaseData* data = (DBaseData*) _data;
static pfBuffer *buffer = NULL;
static int loaded = FALSE;
static pfDCS* dcs1;
static pfDCS* dcs2;
printf("DBaseFunc called:\n");
if ( buffer == NULL ) {
buffer = new pfBuffer;
buffer->select();
}
if ( loaded == FALSE ) {
// create a typical dcs with geode and geoset
// parents must be created before their children
dcs1 = new pfDCS;
data->scene->bufferAddChild(dcs1);
pfGeode* geode1 = new pfGeode;
dcs1->addChild(geode1);
pfGeoSet* geoset1 = new(pfGetSharedArena()) pfGeoSet;
geode1->addGSet(geoset1);
// The work around I have found to the dying DBASE process
// is to call pfBuffer::merge for each and every bufferAddChild.
// This is has a COST as reported in the pfBuffer man pages:
// " pfBuffer::merge will adversely impact the APP process, "
// " proportional to the number of pfBuffer::addChild and "
// " pfBuffer::removeChild requests. "
// BUG WORKAROUND: call merge for first bufferAddChild
pfBuffer::merge();
// create a second dcs with geode and geoset
dcs2 = new pfDCS;
data->scene->bufferAddChild(dcs2);
pfGeode* geode2 = new pfGeode;
dcs2->addChild(geode2);
pfGeoSet* geoset2 = new(pfGetSharedArena()) pfGeoSet;
geode2->addGSet(geoset2);
// BUG WORKAROUND: call merge again for second bufferAddChild()
pfBuffer::merge();
loaded = TRUE;
printf(" Tiles paged IN\n\n");
} else {
data->scene->bufferRemoveChild(dcs1);
pfAsyncDelete(dcs1);
data->scene->bufferRemoveChild(dcs2);
pfAsyncDelete(dcs2);
// when doing only 'bufferRemoveChild'
// a single pfBuffer::merge() at the end seems to be enough.
// bufferRemoveChild don't seem to cause the
// same problem as bufferAddChild() on pfBuffer::merge();
pfBuffer::merge();
loaded = FALSE;
printf(" Tiles paged OUT\n\n");
}
pfDBase();
}
int
main (int argc, char *argv[])
{
float t = 0.0f;
if (argc < 2)
Usage();
// Initialize Performer
pfInit();
// Set up a separate DBASE process
pfMultiprocess( PFMP_FORK_DBASE );
// Load all loader DSO's before pfConfig() forks
pfdInitConverter(argv[1]);
// initiate multi-processing mode set in pfMultiprocess call
// FORKs for Performer processes, CULL and DRAW, etc. happen here.
//
pfConfig();
// Append to Performer search path, PFPATH, files in
// /usr/share/Performer/data */
pfFilePath(".:/usr/share/Performer/data");
pfNode *root = pfdLoadFile(argv[1]);
if (root == NULL)
{
pfExit();
exit(-1);
}
// Attach loaded file to a new pfScene
pfScene* scene = new pfScene;
scene->addChild(root);
// Create a pfLightSource and attach it to scene
scene->addChild(new pfLightSource);
// Configure and open GL window
pfPipe *p = pfGetPipe(0);
pfPipeWindow *pw = new pfPipeWindow(p);
pw->setWinType(PFPWIN_TYPE_X);
pw->setName("IRIS Performer");
pw->setOriginSize(0,0,500,500);
pw->open();
// Create and configure a pfChannel.
pfChannel *chan = new pfChannel(p);
chan->setScene(scene);
chan->setFOV(45.0f, 0.0f);
// determine extent of scene's geometry
pfSphere bsphere;
root->getBound(&bsphere);
chan->setNearFar(1.0f, 10.0f * bsphere.radius);
// set up DBASE callback and passdata
pfDBaseFunc( DBaseFunc );
DBaseData* data = (DBaseData*) pfAllocDBaseData( sizeof(DBaseData) );
data->scene = scene;
// Simulate for twenty seconds.
while (t < 20.0f)
{
pfCoord view;
float s, c;
// Go to sleep until next frame time.
pfSync();
// pass data to DBASE callback
pfPassDBaseData();
// Initiate cull/draw for this frame.
pfFrame();
// Compute new view position.
t = pfGetTime();
pfSinCos(45.0f*t, &s, &c);
view.hpr.set(45.0f*t, -10.0f, 0);
view.xyz.set(2.0f * bsphere.radius * s,
-2.0f * bsphere.radius *c,
0.5f * bsphere.radius);
chan->setView(view.xyz, view.hpr);
}
// Terminate parallel processes and exit
pfExit();
return 0;
}
This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:52:24 PDT