Assertion error in transformState destructor

I get an assertion error (traceback at the end of this post) now and then. It seems a simple setPos causes it (tracking and target are both NodePath instances), but I’m not 100% sure:

self.tracking.setPos( self.target, 0, 0, 0 )

This seems to be a workaround, that is, if I replace the above line with these two lines the assertion error seems to be gone:

t = self.target.getTransform( self.tracking )
self.tracking.setPos( self.tracking, t.getPos( ) )

Does anybody have a clue what is going wrong?
enn0x

EDIT: I use Panda 1.3.2 distribution on Windows.

Assertion failed: _states->find(this) == _saved_entry at line 101 of c:\temp\mkpr\panda3d-1.3.2\panda\src\pgraph\transformState.cxx
Traceback (most recent call last):
  File "TestC.py", line 440, in ?
    base.run( )
  File "C:\Programme\Panda3D-1.3.2\direct\src\showbase\ShowBase.py", line 2028, in run
    self.taskMgr.run()
  File "C:\Programme\Panda3D-1.3.2\direct\src\task\Task.py", line 839, in run
    self.step()
  File "C:\Programme\Panda3D-1.3.2\direct\src\task\Task.py", line 787, in step
    self.__stepThroughList(taskPriList)
  File "C:\Programme\Panda3D-1.3.2\direct\src\task\Task.py", line 721, in __stepThroughList
    ret = self.__executeTask(task)
  File "C:\Programme\Panda3D-1.3.2\direct\src\task\Task.py", line 646, in __executeTask
    endTime = self.trueClock.getShortTime()
AssertionError: _states->find(this) == _saved_entry at line 101 of c:\temp\mkpr\panda3d-1.3.2\panda\src\pgraph\transformState.cxx
shell returned 1

enn0x

This error indicates something very bad has happened within the TransformState cache, to corrupt the cache table. The error isn’t in the setPos() call itself; that is just the time at which the error is detected. The actual error must have occurred some time earlier. It is likely that your workaround is only hiding the underlying problem, not solving it.

Are you doing anything unusual to open a window or set up your graphics state somehow?

Another user has reported a similar crash under fairly isolated circumstances, so I was hoping to be able to research his problem more closely there. It may turn out to be the same thing that’s biting you.

David

I open the window using the “default” way:

from pandac.PandaModules import loadPrcFileData

loadPrcFileData( '', 'win-size 800 600' )
loadPrcFileData( '', 'fullscreen 0' )
loadPrcFileData( '', 'show-frame-rate-meter 1' )
loadPrcFileData( '', 'sync-video 1' )

import direct.directbase.DirectStart

...

game = Game( )
run( )

BUT I am using a self-written C++ extension which basically does the following things:

  • Store a copy of a NodePath instance (value, not pointer)
  • Set location & orientation once a frame using set_mat( )

So far I have two ideas what could happen:

(1) The C++ extension set a “bad” matrix. With bad I mean -/+Inf or NaN in one of the matrix cells.

(2) Since this problem appears only when I run with high frames-per-second (around 600) and not then I sync down to 60 fps, it might be that both my extension and Panda3D try to access the transform at the same time.

My scene graph looks like this:

render
    player ### player root, C++ extension calls set_mat on this NodePath)
        target ### where camera should look at
        dummy ### scaled (1,-1,1) to make ralph look "forward"
            actor ### well, ralph, who else

So what might happen is that the Python code queries “target” transform while at the same time the C++ extension code set the transform for “player”. Hmm… while writing this I see that the extension is compiled with /MT (VC 7.1), that is static multi-threaded. AFAIK Panda3D is compiled single-threaded for Windows.

In both cases it would be my mistake, since the C++ extension is causing it :slight_smile:

So far the problem appears only now-and-then. I know, very fuzzy, but I will try to hunt it down so I can re-produce it. Thanks for the effort anyway.

enn0x

Is your extension threaded, in the sense that you actually spawn a separate thread and manipulate the transform in that thread? If so, then it will certainly cause this sort of crash, and the solution is to compile a custom version of Panda with thread support enabled (which will enable mutexes around the transform manipulations, protecting you from a crash).

If not, then fear not: /MT is the correct compilation parameter, since Panda is built that way also, even though the Panda code itself is not threaded.

David

In the case reported by the other user, it turned out to be a problem caused indirectly by the fact that some DirectX drivers force the FPU into single-precision mode (even though we explicitly ask them not to).

The specific crash was caused by the code creating some transforms before the window opened (and they get written into the cache in double-precision mode), and then later opening a DirectX window (which causes all subsequent cache operations to be performed in single-precision mode). Suddenly, the cache doesn’t match what was previously written to it.

The solution in the other user’s case is to open the window before doing any transform operations, or to use OpenGL, which doesn’t have this problem.

Is it possible this is your problem too?

David

Thanks for the great effort, David.

(1) The extension is not threaded, I mean I don’t create any threads myself or work in any way with threaded code. After compiling with /ML I had one crash, so this has not been the cause, like you explained. I am back to /ML now, to match the way Panda3D is compiled.

Anyway, I have put “compile Panda3D with thread support enabled” on my task list. This will be a good exercise for me. Probably some time after Panda3D 1.4.0 is out.

(2) I use OpenGL, so this is probably not the problem. But I do use single-precision throughout my extension code, and I work with LMatrix4f, LVector3f, LPoint3f. But I will try and first open the window first before doing any other stuff.

My problem is that I can not pin down the error. I didn’t get a crash for several hours now, and if it was crashing it was somewhere during the game loop (hmm… don’t know how to express this right. I mean: not right after loading/starting the game, but after some minutes of game play).

The only thing I know is that it is related to my character controller code. Some parts of the controller work dynamically (e.g. gravity), while other parts work kinematically (e.g. turn or horizontal movement, where forces get applied each frame which are computed from “desired velocity/omega”).

One observation has been that crashes happen only if running without “sync-video 1”. My character turn code is based on mouse movement:

        md = base.win.getPointer( 0 )
        x = md.getX( )
        y = md.getY( )

        if base.win.movePointer( 0, self.centerX, self.centerY ):
            dx = x - self.centerX
            dy = y - self.centerY
        else:
            dx = 0
            dy = 0

If synced I get something like this for dx (small mouse movement to the side):

0
0
1
3
7
11
15
14
11
7
3
1
0
0

If not sync-ed, and running at several hundred fps, I get something like this (several lines of “0” omitted to make it readable):

0
0
0
0
1 <--
0
0
0
0
3 <--
0
0
0
0
7 <--
0
0
0
11 <--
0
0
...

It seems the mouse pointer position gets updated not once a Panda3D-frame, but once every 1/60 secs (or whatever screen refresh rate is ???).

Since the torque applied to the player body is computed from dx, this means that the player turns in a “stutter” way. Maybe the forces and torques simply get too big this way, and the code becomes numerical instable, resulting in NaN/Inf values for the transform matrix.

I will try to average the mouse movement, and see if I get rid of my problem :slight_smile:

Whatever the problem is, I first have to track it down in my code, during the next weeks. I will report back once I can say something more solid. Thank you again for the effort.

enn0x