Game Development Community

Massive lag encountered using PrimBuild... Doing It Wrong?

by Chris Calef · in Torque 3D Professional · 03/07/2011 (4:49 pm) · 16 replies

Hi,

I'm sure some expert here can straighten me out, I'm very confused... I'm using PrimBuild to render the output of a PhysX NxDebugRenderable object. I've had a terrible, nearly unusable lag problem here for quite a while, and today I decided to solve it once and for all. At first, it appeared that my problem was calling the PhysX functions at the wrong time, which made perfect sense and gave me great hope for fixing the problem.

Unfortunately, they have been rearranged, and do not appear to be an issue anymore, but my lag persists.

In my stepPhysics function, which happens once per tick, I'm getting my debugRenderable from PhysX and setting up a global gNumLines and a gLines pointer to store the actual data. Then, I'm calling SceneGraph::getPostRenderSignal().notify() to get a callback to my debug render function after everything else has rendered.

In that function, I'm doing this:
NxU32 kNumLines = gNumLines;
const NxDebugLine *kLines = gLines;

PrimBuild::begin( GFXLineList, gNumLines * 2 );
while ( kNumLines-- )
{
   PrimBuild::color( getDebugColor( kLines->color ) );
   PrimBuild::vertex3fv( &kLines->p0.x );
   PrimBuild::vertex3fv( &kLines->p1.x );
   kLines++;
}
PrimBuild::end();

All of this works fine if I comment out the three PrimBuild lines that do the actual work (color, vertex3fv, vertex3fv) but of course if I do that nothing renders. When they are turned on, however, even with a fairly low number of actual lines being drawn (around 1400 lines, for a total of 2800 verts), my frame rate drops straight through the floor. Within a few seconds, it goes from 70 or 80 fps down to less than ten, often five or less.

Obviously, I'm doing something horribly wrong. Any suggestions?

Thanks in advance,
Chris

#1
03/08/2011 (10:59 am)
Perhaps a better question: does anyone know how I can use a renderInstance (or get a call to prepRenderInstance) if I'm not a SceneObject?

My physics manager needs to get a render call, but it isn't something that should be _in_ the scene. (Sorry, still a GFX newb after all these years...)
#2
03/08/2011 (12:04 pm)
are you sure the lag is render related??

and why not use the torque debug renderer for it?

I have no issue debug rendering my physx player controller and puppet bones, or my physx vehicle doors and panels(all physics, doors flapping and such), using the stock torque debug renderer.

there is a pretty famous physx "one frame lag" between client and server, that can get bad sometimes, especialy with mounted cloth or fluid, and higher speeds.

can you be more specific as to what exactly it is you are trying to render, your col shapes(box vs convex), a lot of the wrong ones, I'm sure you know, can slow you down to a halt.

also avoid rendering things like terrain( you can exclude it as a renderable physics), only render what you need to debug.

creating a whole new sub rendering system, just to render lines for debugging seems a bit extreme, try the stock debug renderer first.

physicsDebugDraw(1);
#3
03/08/2011 (12:10 pm)
re: why not use Torque Debug renderer, A: because I don't know squat about it, and am blundering around in the dark here. :-) Because there are still no real engine coding docs AFAIK (unless they are sitting right in front of my face and I haven't stumbled across them yet?)

I know it can't be an actual render lag problem, it's got to be a 100% "doing it wrong" problem, because I've had this working multiple times through the various permutations of the engine, it's only when I tried it the last time for T3D that I hit a wall of lag. It's a very finite set of boxes I'm trying to render, which should never cause anything as dramatic as what I'm experiencing.

Going off to find more info on debug renderer. Got any quick samples you can point to, to help a bro out?

#4
03/08/2011 (12:14 pm)
Chris,this is a code that I use to draw lines:

#include "gfx/sim/debugDraw.h"

..
DebugDrawer *drawer = DebugDrawer::get();
drawer->setLastTTL(DebugDrawer::DD_INFINITE);
ColorI color = ColorI( 255, 255, 255, 64 );
drawer->drawLine(Point1,Point2,color);
#5
03/08/2011 (12:15 pm)
Awesome... so, does that have to be done every frame, in a function connected to prepRenderImage, or is there a way I can feed it verts and indices and have it keep drawing that until I change it a few frames later?
#6
03/08/2011 (12:16 pm)
My problem is I'm doing this with a physics manager object which is *not* a SceneObject, and doesn't want to be.
#7
03/08/2011 (12:18 pm)
I was exactly where you are Chris, older versions where fine,
seems no-one knows who changed what and why and when, between beta's.

I stumbled across physicsDebugDraw purely by chance, and it was a lucky chance,
you'll see some of my older threads pleading for someone to help me render physics...

throw physicsDebugDraw(1); into console, go from there, is all I can offer, GFX scares me too much still

#8
03/08/2011 (12:18 pm)
I am not sure,for optimization purposes I use to draw lines per ticks.
#9
03/08/2011 (12:19 pm)
Well, that's what I want to do as well, so if it worked for you without flickering (as the between-tick frames overwrite the renderings per tick) then it's probably what I want. Testing...
#10
03/08/2011 (12:20 pm)
Quote:GFX scares me too much still

Hehe, don't I know it...
#11
03/08/2011 (12:36 pm)
@Ivan: Is there any setup you do to the DebugDrawer the first time to make that work, or flushing etc. you need to do after each pass?

My first attempt crashed, going to debug mode...
#12
03/08/2011 (12:40 pm)
No,I'm using directly that way.
I usually draw around 20-30 lines.

By the way there are several other ways to draw lines,for example the GFX drawer:

#include "gfx/gfxDrawUtil.h"
GFXDrawUtil *drawer = GFX->getDrawUtil();
#13
03/08/2011 (1:39 pm)
Hmm, thanks, I'll look into that one too. The one I need is the one that doesn't have to be called every frame from a prepRenderImage or equivalent...

Sounds like DebugDrawer is the winner:
/// Internally, DebugDrawer maintains a list of active debug primitives, and draws the
/// contents of the list after each frame is done rendering.
#14
03/08/2011 (3:15 pm)
Hm, well on actual testing, it looks like DebugDrawer is no help. It does exactly the same thing behind the scenes that I was doing in my function: calls PrimBuild::begin, color, vertex3fv and then PrimBuild::end. And it takes even longer to get it done than I was, when I try to draw only 240 lines this way my framerate drops off the charts again, from over 100 to less than 5 in seconds.

I guess we'll see how we do with GFXDrawUtil after all...

Edit: also, DebugDrawer seems to get turned off when the mission editor is turned on, or else the editor simply renders later somehow... this is a familiar problem from an earlier incarnation of my debug renderer, but I still haven't figured out why/how it happens.
#15
03/08/2011 (4:03 pm)
Well, backing up a bit, it appears that perhaps a little RTFM might be in order (in this case "the manual" being code comments). In primBuilder.h, I see:

/// There are two ways to use it. You can use the begin()
/// and end() calls to have it draw immediately after calling
/// end(). This is the "OpenGL" or "immediate" style of usage.
///
/// The other way to use this is to use the beginToBuffer()
/// and endToBuffer() calls, which let you store the
/// results of your intermediate calls for later use.
/// This is much more efficient than using the immediate style.


THAT appears promising. Unfortunately there does not seem to be a single example of it working anywhere in the engine source code, so we're back down to the GFX layer.

EDIT: Cancel the part about the SceneObject / getting a render call "problem", momentarily forgot I had already solved that a long time ago... :-P

It looks like this:
SceneGraph::getPostRenderSignal().notify( &nxPhysManager::renderDebug );
#16
03/09/2011 (1:14 am)
Wow, well, this was a long day to come up with maybe twenty lines max of useful code - but the problem is solved, at least in rough form. For anyone following along who has similar problems, my conclusions were:

None of the above methods for drawing lines helped at all. DebugDrawer *drawer, GFXDrawUtil *drawer, and PrimBuild beginToBuffer/endToBuffer were all horrendously slow when given a problem on the scale of a few hundred primitives (unless I'm still doing something wrong that I never discovered). All of my logic worked without lag until I uncommented the actual calls to drawer or PrimBuild, though, so I'm having a hard time finding anything else on which to blame the slowdown.

PrimBuild started to work a little better when I stopped trying to do it every frame, and instead backed out to every tick, but since endToBuffer creates a volatile GFXVertexBuffer that disappears after the first use, I found I was going to have to copy all the vertices into a dynamic buffer in order to have something to render on all the frames in between ticks - without doing that, the result was the expected flickering as the between-tick frames overwrote the frames that had debug render data.

Once I started thinking about copying the verts out of the volatile vertex buffer, I realized there was no advantage left for using PrimBuild at all, so I just stuff my verts into a new dynamic buffer and used that instead. I still haven't figured out how to clear a buffer so that I can use it again with a different size, since dynamic buffers are forever locked into the size they started at. But here is a summary of what I ended up with.

I declared a global vertex buffer handle, to store the verts:
GFXVertexBufferHandle<GFXVertexPCT> gDebugVerts;

In the once-per-tick physics step function, I allocate gDebugVerts based on the number of lines I have from my physx debug renderable, and then stuff it with current vertex colors and positions, and tell the SceneGraph to call my renderDebug function at post render time:
gDebugVerts.set( GFX, gNumLines * 2, GFXBufferTypeDynamic );
U32 v=0;
GFXVertexPCT *verts = gDebugVerts.lock();
while ( kNumLines-- )
{
	verts[v].color = getDebugColor( kLines->color );
	verts[v++].point = Point3F(kLines->p0.x,kLines->p0.y,kLines->p0.z);
	verts[v].color = getDebugColor( kLines->color );
	verts[v++].point = Point3F(kLines->p1.x,kLines->p1.y,kLines->p1.z);
	kLines++;
}
gDebugVerts.unlock();
SceneGraph::getPostRenderSignal().notify( &nxPhysManager::renderDebug );

Then, in the renderDebug function, I just have to stuff that vertex buffer into GFX and tell it to draw:
GFX->setVertexBuffer(gDebugVerts);
GFX->drawPrimitive(GFXLineList, 0, gNumLines);

Now, as soon as I get some sleep and some morning coffee in me I hope to figure out how to clear that gDebugVerts thing out so it can be reallocated, because this will break as soon as we change the number of objects in the debug visualization... but I'm assuming that isn't going to take as long to figure out as this part did. :-|

Cheers, hope it helps somebody.


--------------

EDIT: As expected, after a little sleep and morning coffee, it became evident that I don't have to worry about manually freeing the dynamic buffer, apparently you can just call .set() on the same VertexBufferHandle again, and GFX just throws the other one away. (Please correct me if I'm wrong!!) So far at least I've seen no negative effects.