Streamed IO and LOD City Demo
Streamed IO and LOD City Demo
I have made a streamed LOD scene node that handles memory usage and LOD of meshes and textures it loads asynchronously on a separate thread, i didn't not modify the irrlicht loaders, just some small ponts to make it work across all the drivers safely (most of the logic is at node level). i just want you guys to test it to see if it is really safe.
Just move away from the cube to change lod level (also nearer), only one mesh and one texture are in memory at anyone time.
you will see this in your os memory monitor and also the fact that irrlicht has to reload previously deleted data. IO is streamed and the lod change wont take place till the io is compeletly done for the required LOD level (useful for big detail changes ie: from 5 megs to 20 megs)
It also says streaming twice at each lod switch because i have two scenenodes in the same place to test thread safety while lod'ing multiple meshes at the same time.
http://www.mediafire.com/?sharekey=9ce4 ... b9a8902bda
just unzip and open terminal
do
./demo
to run. (make sure you have pthreads installed which is most people)
Sorry about the simple demo im short on time, just imagine it being applied to city buildings for something like GTA.
Just move away from the cube to change lod level (also nearer), only one mesh and one texture are in memory at anyone time.
you will see this in your os memory monitor and also the fact that irrlicht has to reload previously deleted data. IO is streamed and the lod change wont take place till the io is compeletly done for the required LOD level (useful for big detail changes ie: from 5 megs to 20 megs)
It also says streaming twice at each lod switch because i have two scenenodes in the same place to test thread safety while lod'ing multiple meshes at the same time.
http://www.mediafire.com/?sharekey=9ce4 ... b9a8902bda
just unzip and open terminal
do
./demo
to run. (make sure you have pthreads installed which is most people)
Sorry about the simple demo im short on time, just imagine it being applied to city buildings for something like GTA.
Last edited by omaremad on Sat Oct 25, 2008 6:24 pm, edited 2 times in total.
"Irrlicht is obese"
If you want modern rendering techniques learn how to make them or go to the engine next door =p
If you want modern rendering techniques learn how to make them or go to the engine next door =p
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
Ditto; I'd love to try this out on Windows, and more importantly, see the source.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
The windows implmentation of pthreads is a bit different (mutexes dont seem to pause other threads ) so i only included one streamed building. Sorry for how crap the demo is... it would look nicer with an actual finished model.
The low LOD has a red 256 texture, high LOD has a white 1024 texture, im guessing mipmapping can be disabled to reduce texture wastage since we are streaming the LOD for textures too.
Polycounts are double (see window caption and console for proof of streaming) Also if you have multi cpu the cpu meters in task manger should spike.
Source wont be released till i get time to fix this bug and also test on other peoples cpu's.
http://www.mediafire.com/file/my2mnfwyzn2/thread.zip <windows
The low LOD has a red 256 texture, high LOD has a white 1024 texture, im guessing mipmapping can be disabled to reduce texture wastage since we are streaming the LOD for textures too.
Polycounts are double (see window caption and console for proof of streaming) Also if you have multi cpu the cpu meters in task manger should spike.
Source wont be released till i get time to fix this bug and also test on other peoples cpu's.
http://www.mediafire.com/file/my2mnfwyzn2/thread.zip <windows
"Irrlicht is obese"
If you want modern rendering techniques learn how to make them or go to the engine next door =p
If you want modern rendering techniques learn how to make them or go to the engine next door =p
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
Oh, I'll wait until then.omaremad wrote:Source wont be released till i get time to fix this bug and also test on other peoples cpu's.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
If you are interested in the concept its like this:
Requirement:
Make minimum number of irrlicht calls from a thread other than the main one (bc of irr is not thread safe)
So what really needs to be threaded?
IO<- so slow esp with step by step reading and pasing.
So i use a mutex on the smgr->getMesh(), this allows one mesh and its textures to be loaded at one time a "global mutex", there is however some complications... one being no opengl calls are allowed from other threads unless they own the context.
So what i do is only load the textures to ram using the IO thread (simple modification to nulldriver.cpp getTexture() ) and have a textureQue in the driver which uploads the data to the gpu when the main thread finishes the current frame.
Once the data is loaded the io thread signals the main thread to switch the mesh pointers in the custom scenenode and delete the old mesh and its textures(monitors refrence count to see if its used by other nodes).
Requirement:
Make minimum number of irrlicht calls from a thread other than the main one (bc of irr is not thread safe)
So what really needs to be threaded?
IO<- so slow esp with step by step reading and pasing.
So i use a mutex on the smgr->getMesh(), this allows one mesh and its textures to be loaded at one time a "global mutex", there is however some complications... one being no opengl calls are allowed from other threads unless they own the context.
So what i do is only load the textures to ram using the IO thread (simple modification to nulldriver.cpp getTexture() ) and have a textureQue in the driver which uploads the data to the gpu when the main thread finishes the current frame.
Once the data is loaded the io thread signals the main thread to switch the mesh pointers in the custom scenenode and delete the old mesh and its textures(monitors refrence count to see if its used by other nodes).
"Irrlicht is obese"
If you want modern rendering techniques learn how to make them or go to the engine next door =p
If you want modern rendering techniques learn how to make them or go to the engine next door =p
That looks pretty cool, no observable slow down when it changes LOD. So presumably when you're streaming in the new data you're removing and deleting the old stuff yeah?
Looks good with one building though i wonder if it would suffer a bit with trying to do a whole city at all? Might have to handle lots of LOD changes at once but maybe you just need to design the LOD switching so it happens minimally.
Looks good with one building though i wonder if it would suffer a bit with trying to do a whole city at all? Might have to handle lots of LOD changes at once but maybe you just need to design the LOD switching so it happens minimally.
-
- Posts: 153
- Joined: Mon Mar 03, 2008 8:42 am
- Location: Suceava - Romania
- Contact:
-
- Posts: 1638
- Joined: Mon Apr 30, 2007 3:24 am
- Location: Montreal, CANADA
- Contact:
That is really nice.
For the load stream feature, I would have to test this with a bigger scene to check. Right now the mesh is so small, that I don't notice the streaming loading process (also the camera is behind the mesh so we have to turn around to see it)
The LOD is really working well.
good work!
For the load stream feature, I would have to test this with a bigger scene to check. Right now the mesh is so small, that I don't notice the streaming loading process (also the camera is behind the mesh so we have to turn around to see it)
The LOD is really working well.
good work!
Yeah, if you wanted to read more on it, then you could read the whitepaper by Insomniac Games on there streaming system. They basically stream in data when at least 1-4 fragments would be visible on screen (to reduce the pop in.) And they also set a time for how long the object would have to be non-visible before it was removed from memory.JP wrote:That looks pretty cool, no observable slow down when it changes LOD. So presumably when you're streaming in the new data you're removing and deleting the old stuff yeah?
Looks good with one building though i wonder if it would suffer a bit with trying to do a whole city at all? Might have to handle lots of LOD changes at once but maybe you just need to design the LOD switching so it happens minimally.
TheQuestion = 2B || !2B
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
That's a curiously passive strategy. If you're truly concerned about memory, then you really have to know how much memory you've got available, and free up as necessary to stay within the limit.Halifax wrote:And they also set a time for how long the object would have to be non-visible before it was removed from memory.
The corollary of that is that since freeing is a relatively cheap operation compared to (re)loading, if know when you have to free, then you don't free anything until you have to.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Ah yes rogerborg, you caught me slipping. All textures do include a stale timer for how long it hasn't been visible, but it is only used when textures need to be removed. And the only time that happens is when a new texture has to be streamed in.rogerborg wrote:That's a curiously passive strategy. If you're truly concerned about memory, then you really have to know how much memory you've got available, and free up as necessary to stay within the limit.Halifax wrote:And they also set a time for how long the object would have to be non-visible before it was removed from memory.
The corollary of that is that since freeing is a relatively cheap operation compared to (re)loading, if know when you have to free, then you don't free anything until you have to.
TheQuestion = 2B || !2B
Manged to get some time. I used valgrind to get rid of the leaks, it only leaks now if you close the application mid-streaming which shouldn't be a problem(the application's ram is reclaimed as it dies).
here is the source, it will not run on hardware accelrated modes unless you modify irrlicht with some simple modifications, but the code should work fine in software modes with a normal irrlicht (untested)
Its probably not very useful in its current form (ill make a proper release when i have time), bit i think you guys are interested in the source.
Irrlicht and pthreads are needed of course.
here is the source, it will not run on hardware accelrated modes unless you modify irrlicht with some simple modifications, but the code should work fine in software modes with a normal irrlicht (untested)
Its probably not very useful in its current form (ill make a proper release when i have time), bit i think you guys are interested in the source.
Irrlicht and pthreads are needed of course.
Code: Select all
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#include <pthread.h>
scene::ISceneManager* smgr;
//a struct to carry arguemnts across threads
struct arguments
{
c8* name;
scene::IAnimatedMesh* oldMesh;
scene::IAnimatedMesh** smesh;
core::aabbox3d<f32>* sBox;
scene::ISceneManager* ssmgr;
volatile bool* switching;
};
//lod struct for setting distances and meshes
struct lodLevel
{
c8* meshName;
float distance;
};
arguments argt;
//allows one streamer thread at a time.
volatile bool switching=false;
void isswitching(bool in)
{
switching=in;
};
class CStrreamedLODSceneNode : public scene::ISceneNode
{
pthread_t thread;
core::aabbox3d<f32> Box;
video::SMaterial Material;
scene::IAnimatedMesh* mesh;
scene::IAnimatedMesh* streamedMesh;
scene::ISceneManager* mgr;
int currentLOD;
core::array<lodLevel> levels;
volatile bool switchMeshes;
bool ready;
public:
CStrreamedLODSceneNode(scene::ISceneNode* parent, scene::ISceneManager* smgr, s32 id)
: scene::ISceneNode(parent, smgr, id)
{
mgr=smgr;
Material.Wireframe = false;
Material.Lighting = false;
//Material.MaterialType=video::EMT_LIGHTMAP;
mesh=mgr->getMesh("2.obj");
mesh->grab();
lodLevel Low;
Low.meshName="2.obj";
Low.distance=0;
lodLevel High;
High.meshName="1.obj";
High.distance=500;
levels.push_back(Low);
levels.push_back(High);
currentLOD=0;
Box=mesh->getMesh(0)->getBoundingBox();
switchMeshes=false;
ready=true;
}
virtual ~CStrreamedLODSceneNode()
{
mesh->drop();
}
virtual void OnRegisterSceneNode()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this);
}
ISceneNode::OnRegisterSceneNode();
}
virtual void render()
{
//LOD logic
handleLOD();
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
//If there is freshly streamed data use it instead of current data
if (switchMeshes)
switchData();
for (int i =0; i<mesh->getMesh(0)->getMeshBufferCount();i++)
{
mesh->getMesh(0)->getMeshBuffer(i)->getMaterial().Lighting=false;
driver->setMaterial(mesh->getMesh(0)->getMeshBuffer(i)->getMaterial());
driver->drawMeshBuffer(mesh->getMesh(0)->getMeshBuffer(i));
}
}
virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}
virtual u32 getMaterialCount() const
{
return 1;
}
virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}
void handleLOD()
{
//NB makesure your mesh is centered around the origin, if not use the bounding box
//centre instead of getPosition()
core::vector3df camPos= mgr->getActiveCamera()->getPosition();
float distance = core::vector3df(camPos-getPosition()).getLength();
int requiredLevel=0;
for (int i=0; i<levels.size();i++)
{
if (distance>levels[i].distance)
{
requiredLevel=i;
}
}
if (requiredLevel!=currentLOD)
{
//If failed then another node instance is streaming.
//Streaming will happen the consequent frame since currentLOD is still != requiredLevel
if (streamMesh(levels[requiredLevel].meshName))
currentLOD=requiredLevel;
}
}
bool streamMesh(c8* name)
{
argt.name = name;
argt.oldMesh = mesh;
argt.smesh = &streamedMesh;
argt.sBox= &Box;
argt.ssmgr = this->mgr;
argt.switching=&switchMeshes;
//while (CStrreamedLODSceneNode::switching){};
if (!switching)
{
ready = false;
this->mgr->getMesh(name);
pthread_create( &thread, NULL, callback, (void*)&argt);
return true;
}
else return false;
}
void switchData()
{
mesh->drop();
if (mesh->getReferenceCount()==1)
{
for (int i =0; i<mesh->getMesh(0)->getMeshBufferCount();i++)
{
//clean out unsed textures (by layer)
for (int t=0;t<4;t++)
{
video::ITexture* tex=mesh->getMesh(0)->getMeshBuffer(i)->getMaterial().getTexture(t);
if (tex)
{
int cnt=tex->getReferenceCount();
if (cnt==1)
mgr->getVideoDriver()->removeTexture(mesh->getMesh(0)->getMeshBuffer(i)->getMaterial().getTexture(t));
}
}
}
mgr->getMeshCache()->removeMesh(mesh);
}
mesh=streamedMesh;
switchMeshes=false;
ready = true;
}
static void* callback(void* iarg)
{
isswitching(true);
arguments ar;
ar=*(arguments*)iarg;
printf("Streaming\n");
scene::IAnimatedMesh* tempMesh = ar.ssmgr->getMesh(ar.name);
*ar.smesh=tempMesh;
tempMesh->grab();
isswitching(false);
*ar.switching=true;
if (!pthread_detach( pthread_self()) )
return NULL;
}
};
int main()
{
// let user select driver type
video::E_DRIVER_TYPE driverType;
printf("Please select the driver you want for this example:\n"\
" (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
char i;
std::cin >> i;
switch (i)
{
case 'c':
driverType = video::EDT_OPENGL;
break;
case 'd':
driverType = video::EDT_SOFTWARE;
break;
case 'e':
driverType = video::EDT_BURNINGSVIDEO;
break;
case 'f':
driverType = video::EDT_NULL;
break;
default:
return 0;
}
// create device
IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480), 32, false);
if (device == 0)
return 1; // could not create selected driver.
// create engine and camera
device->setWindowCaption(L"Streamed io and LOD -Omaremad");
video::IVideoDriver* driver = device->getVideoDriver();
smgr = device->getSceneManager();
smgr->addCameraSceneNodeFPS(0)->setPosition(core::vector3df(100,100,100));
CStrreamedLODSceneNode *myNode =
new CStrreamedLODSceneNode(smgr->getRootSceneNode(), smgr,4);
CStrreamedLODSceneNode *myNode2 =
new CStrreamedLODSceneNode(smgr->getRootSceneNode(), smgr,5);
myNode2->setScale(core::vector3df(50,50,50));
myNode->setScale(core::vector3df(50,50,50));
u32 frames=0;
while (device->run())
{
driver->beginScene(true, true, video::SColor(0,100,0,100));
smgr->drawAll();
driver->endScene();
if (++frames==100)
{
core::stringw str = L"Irrlicht Engine [";
str += driver->getName();
str += L"] FPS: ";
str += (s32)driver->getFPS();
device->setWindowCaption(str.c_str());
frames=0;
}
}
myNode->drop();
myNode2->drop();
device->drop();
pthread_exit(0);
return 0;
}
"Irrlicht is obese"
If you want modern rendering techniques learn how to make them or go to the engine next door =p
If you want modern rendering techniques learn how to make them or go to the engine next door =p
Here is a demo shows its application to a city.
The meshes were made automtaically in blender using discombulator script, and exported using irrb(i modfied it with a vertex dictionary so i can export vert colors). The meshes are subdevided once and saved in the ascii .irrmesh format to add more bulk to them (to stress the streaming). Normals made in InsaneBump
On windows texture creation in opengl/dx is very slow so i added a third thread to handle slow driver commands.
thread one: rendering-always running
thread two: streams the meshes and textures and adds them to the upload to gpu list - created when needed.
thread three: creates and uploads gpu textures-always running
The shader is a single light version of TGMS one
I really like this bit he used, gives a nice colour tint.
http://www.mediafire.com/file/r0qhzyyumho/gta.zip
vista only
The meshes were made automtaically in blender using discombulator script, and exported using irrb(i modfied it with a vertex dictionary so i can export vert colors). The meshes are subdevided once and saved in the ascii .irrmesh format to add more bulk to them (to stress the streaming). Normals made in InsaneBump
On windows texture creation in opengl/dx is very slow so i added a third thread to handle slow driver commands.
thread one: rendering-always running
thread two: streams the meshes and textures and adds them to the upload to gpu list - created when needed.
thread three: creates and uploads gpu textures-always running
The shader is a single light version of TGMS one
I really like this bit he used, gives a nice colour tint.
Code: Select all
" if(color.r>1.0){color.gb+=color.r-1.0;}"
" if(color.g>1.0){color.rb+=color.g-1.0;}"
" if(color.b>1.0){color.rg+=color.b-1.0;}"
vista only
"Irrlicht is obese"
If you want modern rendering techniques learn how to make them or go to the engine next door =p
If you want modern rendering techniques learn how to make them or go to the engine next door =p