Page 1 of 3

[fixed]TextureMatrix bug

Posted: Tue Jun 19, 2007 2:39 am
by NoName4ever
Hi!

I was playing with Irr 1.3 for sometime and in love with its simplicity. But I can't use it for my project now because of TextureMatrix bug.

How to reproduce:

1. Download Irr 1.3
2. Load Irrlicht8.0.sln using VS.NET 2005 SP1 (Vista box)
3. Add Examples/Movement demo
4. Go to line 123 and add this line after it:

Code: Select all

node->getMaterial(0).getTextureMatrix(0).setTextureScale(30,30);
5. Compile and run in Debug mode.

The bugs:

1. It always crash upon exit.
The SS of Visual Studio:

Image

2. The texture showed is erroneous in D3D9 and OpenGL 1.5 but it seem to look fine in Burning Software Renderer.

Erroneous texture SS:

Image

Posted: Tue Jun 19, 2007 5:28 am
by vitek
The problem is that the memory for the texture matrix is allocated from a different heap than it is freed to. The call node->getMaterial(0).getTextureMatrix(0).setTextureScale(30,30) results in a call to the inline function...

Code: Select all

core::matrix4& getTextureMatrix(u32 i)
{
  if (i<MATERIAL_MAX_TEXTURES && !TextureMatrix[i])
    TextureMatrix[i] = new core::matrix4(core::matrix4::EM4CONST_IDENTITY);
  return *TextureMatrix[i];
}
So the call to new is compiled into the executable.

The CMeshBuffer and SMaterial destructors are inline, so they are likely compiled into the function that calls them. The CCubeSceneNode/CSphereSceneNode destructor is compiled into the Irrlicht.dll.

So the allocation comes from the heap that is in the executable, but the deallocation is being done by the heap that is in the dll. To fix, you would end up writing some of the SMaterial methods out of line so that they are compiled into the Irrlicht dll.

Travis

Posted: Tue Jun 19, 2007 7:43 am
by hybrid
Ah, that's why I could not reproduce it. Linux handles even libraries inside each process context. Is there any other chance besides making the allocation/deallocation methods part of the dll? What about compiler decisions about inline - methods can even be inlined without the keyword in front (or being part of the class definition).

Posted: Tue Jun 19, 2007 5:32 pm
by vitek
Well, the inline keyword is just a hint to the compiler that you'd like a method inlined where it is used. If you write a function inside a class declaration, it is implicitly inlined.

You could write a function to allocate memory from the Irrlicht.dll heap and a matching function to release memory to the Irrlicht.dll heap. Then call those functions. I don't think it makes sense for the material to own an allocator, and even if it did, I'm not absolutely convinced that the irrAllocator actually solves the dll boundary problem.

Travis

Posted: Wed Jun 20, 2007 6:18 am
by robarnold
I came across this bug as well. Another solution is to recompile Irrlicht.dll with the multithreaded dll crt instead of the multithreaded crt. Now all allocations between irrlicht and your executable (assuming you use the multithreaded dll crt) will use the same heap.

You can change this setting in visual studio by going to the project properties, C/C++, Code Generation, Runtime Library.

As for the second problem, I ran across this too. In each hardware driver (ogl/d3d)'s setTransform method, there is a check made against texture matrices for the identity matrix and the call returns early if the given matrix is the identity. This seems like it was intended to be an optimization for the common case (since SMaterial::getTextureMatrix will return an identity matrix) where no texture matrix is set. However in my own project (and presumably the example), the texture matrix needs to be set to the identity because the current texture transform is not the identity.

I see two quick workarounds: comment out the check or twiddle your identity matrices (assuming you know when they are the identity) so that they appear to not be the identity matrix; this is actually rather difficult since matrix4::isIdentity tries hard to get the right answer. I feel much better about the former solution than the latter.

Posted: Wed Jun 20, 2007 7:12 am
by hybrid
The reset has been fixed recently. It did not make it into the 1.3.1 release, but it's at least fixed in SVN. Seems indeed like an optimization, but a proper reset is definitely needed.

Posted: Wed Jun 20, 2007 1:29 pm
by NoName4ever
Thanks for all replies. I will try them today.

Posted: Wed Jun 20, 2007 4:55 pm
by NoName4ever
Thanks guys! It works like charm now.

But I felt that those kind of bug should be well eliminated in 1.31. Maybe we need more defensive update? (Test more before releasing). I've been using OGRE for years without any major issues.

Posted: Wed Jun 20, 2007 9:12 pm
by hybrid
The thing is that we do not have examples for all features of Irrlicht. Moreover, the bug did not show up in my example. At least not all the time. I saw it some time ago, but since I'm not constantly working at the same machine I did not track it down to the end. But as you see, if someone reproduces this problem it's often fixed quite fast. the reason it was not fixed in 1.3.1 was simply the overlapping of the test phase of 1.3.1 and the bug fix. I was some days late.

Posted: Wed Jan 02, 2008 5:32 pm
by Yustme
Hi guys,

I'm having this problem too at the moment and i'm using version 1.4.

I was trying to scale a texture.

This is how i tried it:

Code: Select all

if(wall)
	{
		CMatrix4<f32> scaleTexture;
		scaleTexture.makeIdentity();
		scaleTexture.setTextureScale(16,16);
		wall->setMaterialFlag(video::EMF_LIGHTING, false);
		wall->setMaterialTexture(0, driver->getTexture("poolTabel.jpg"));
		wall->getMaterial(0).setTextureMatrix(0, scaleTexture);
		wall->setVisible(visible);
	}
Works fine, but when i'm trying to exit the game, it crashes and pointing to line 119 "delete this" in header file: ireferencecounted.h.

Runtime error message:
Windows has triggered a breakpoint in game.exe.

This may be due to a corruption of the heap, and indicates a bug in game.exe or any of the DLLs it has loaded.

The output window may have more diagnostic information
I dont quite understand the work arounds previously mentioned.

Can somebody explain me how to fix this?

Thanks in advance!

Posted: Wed Jan 02, 2008 7:09 pm
by vitek
I suggest you try commenting out the call to setTexureMatrix(). If the failure goes away, then you have a pretty good indicator of what is causing the problem. If the failure remains, then you need to look elsewhere.

It might also help if you had a look at the stack trace. It will tell you what functions were called that led up to the failure.

Honestly, I don't think the problem is actually fixed. A correct solution would require the deallocation routine to use the same heap as the allocation routine. The destructor of some of the Irrlicht provided scene nodes will delete the texture matrices, and this delete happens inside the dll heap. The call to setTextureMatrix() is still inlined, and it is still in the user executable, so the call to allocate the matrix can still be inlined.

Of course the other solution would be to make sure that the user executable and the dll both use the same shared runtime library flag [/MD in MSVC].

Travis

Posted: Wed Jan 02, 2008 7:47 pm
by Yustme
Hi Travis,

I've looked a few times in the stacktrace, but i found nothing useful.

Stacktrace:

Code: Select all

 	ntdll.dll!7c901230() 	
 	[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]	
 	ntdll.dll!7c96c943() 	
 	ntdll.dll!7c96cd80() 	
 	ntdll.dll!7c96df66() 	
 	ntdll.dll!7c96e0f0() 	
 	ntdll.dll!7c94a5d0() 	
 	ntdll.dll!7c96e0d4() 	
 	ntdll.dll!7c94a5d0() 	
 	ntdll.dll!7c926abe() 	
 	ntdll.dll!7c91056d() 	
 	ntdll.dll!7c926abe() 	
 	ntdll.dll!7c9268ad() 	
 	ntdll.dll!7c91056d() 	
 	ntdll.dll!7c9268ad() 	
 	ntdll.dll!7c926abe() 	
 	ntdll.dll!7c9268ad() 	
 	ntdll.dll!7c91056d() 	
 	ntdll.dll!7c91056d() 	
 	kernel32.dll!7c80997a() 	
 	kernel32.dll!7c80998d() 	
 	d3d9.dll!4fdfb208() 	
 	Irrlicht.dll!00544882() 	
 	Irrlicht.dll!00498bfc() 	
 	Irrlicht.dll!004dced1() 	
 	Irrlicht.dll!0049e3b2() 	
 	Irrlicht.dll!0049df1a() 	
 	Irrlicht.dll!004a03f7() 	
 	Irrlicht.dll!0049ff05() 	
 	Irrlicht.dll!00515ec9() 	
 	Irrlicht.dll!00517028() 	
>	game.exe!irr::IReferenceCounted::drop()  Line 119 + 0x34 bytes	C++
 	game.exe!main(int argc=1, char * * argv=0x003a5e70)  Line 369	C++
 	game.exe!__tmainCRTStartup()  Line 597 + 0x19 bytes	C
 	game.exe!mainCRTStartup()  Line 414	C
 	kernel32.dll!7c816ff7() 	
This runtime error happens right after "device->drop".

If i comment the line:

wall->getMaterial(0).setTextureMatrix(0, scaleTexture);

Then the error doesn't show up.

The "runtime library flag [/MD in MSVC]" is standard set on this value, that didn't fixed the bug either.

Posted: Sun Mar 02, 2008 8:54 am
by BlindSide
How about you make it so that TextureMatrices are initialised at startup regardless of whether they are in use or not, instead of when they are first modified. 64 bytes is really not something to fuss over, especially when it introduces this kind of inconvenience.

Posted: Sun Mar 02, 2008 9:47 am
by hybrid
It's 64*4*#materials (or 64*8 if you want more textures). Since materials are reproduced for each meshbuffer this will lead to quite some memory consumption.

Posted: Sun Mar 02, 2008 10:07 am
by BlindSide
Ok I will have to think of a better solution for this. How about a helper function that returns the texture matrices through irrlicht? Like:

Code: Select all

driver->getTextureMatrixOfMaterial(SMaterial& material);
That should fix it right?

The reason I want to get this sorted out is because I plan to use the TextureLayer TextureMatrix as the interface for supplying the projective matrix in my projective texturing addition.