[MDX] Memory exceptions when locking/unlocking textures

Started by
3 comments, last by sirob 17 years, 6 months ago
Hello. I'm having some trouble with a function I've created to join two textures together:

protected void Add( TextureDefinition.PatchDescriptor DescriptorReference )
        {
		Patch Patch = Resources.GetPatch( DescriptorReference.PatchNumber );
        	if( Patch == null )
        	{
        		return;
        	}
        	int R, G, B, A;
        	DirectX.GraphicsStream Stream = Texture.LockRectangle( 0, Direct3D.LockFlags.None );
        	DirectX.GraphicsStream PatchStream = Patch.Texture.LockRectangle( 0, Direct3D.LockFlags.None );
        	for( int y = 0, ty = DescriptorReference.Y; y < Patch.Height && ty < Height; y++, ty++ )
        	{
        		for( int x = 0, tx = DescriptorReference.X; x < Patch.Width && tx < Width; x++, tx++ )
        		{
        			PatchStream.Position = ( ( y * Patch.Width ) + x ) * 4;
        			R = PatchStream.ReadByte();
        			G = PatchStream.ReadByte();
        			B = PatchStream.ReadByte();
        			A = PatchStream.ReadByte();
        			if( A == 255 )
        			{
        				Stream.Position = ( ( ty * Width ) + tx ) * 4;
        				Stream.WriteByte( (byte)R );
        				Stream.WriteByte( (byte)G );
        				Stream.WriteByte( (byte)B );
        				Stream.WriteByte( (byte)A );
        			}
        		}
        	}
        	PatchStream.Close();
        	Patch.Texture.UnlockRectangle( 0 );
		Stream.Close();	
        	Texture.UnlockRectangle( 0 );
        	return;
        }

The problem is that sometimes one of the UnlockRectangle calls will cause an exception "Exception System.AccessViolationException was thrown in debuggee: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.". Also occasionally I get the same exception on one of the Stream.WriteByte calls, which seems odd considering all the bounds checking I checked the MSDN and as usual there wasn't much there(this exception isn't even listed under the possible Exceptions). My textures are created like this: Texture = new Direct3D.Texture( Game.Device, Width, Height, 1, Direct3D.Usage.SoftwareProcessing, Direct3D.Format.A8R8G8B8, Direct3D.Pool.Managed ); Any help is appreciated.
Advertisement
I can see a couple things here:
1) You're not using the pitch returned by lock call. You'll need to use a different overload to have it returned, but it is highly recommended you use the pitch value when writing/reading from textures or surfaces.

2) Does GraphicsStream::Position take a value in bytes? I wouldn't be surprised if it took an index of the item to set it to, in which case your * 4 would make you go out of bounds.

Also, you mention it only fails some of the times. What happens when you get no error? Do the results match what you expect it to do?

Hope this helps [smile].
Sirob Yes.» - status: Work-O-Rama.
Almost forgot, I once had a hellish time trying to lock two buffers at the same time with MDX2. One of my conclusions was that it might not be possible. If none of the options I mentioned works, perhaps you could try locking the read first, copying the data to a temporary array, and then writing it after unlocking the read texture.

Hope this helps.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
I can see a couple things here:
1) You're not using the pitch returned by lock call. You'll need to use a different overload to have it returned, but it is highly recommended you use the pitch value when writing/reading from textures or surfaces.


But then how would I use it? Add it to GraphicsStream.Position?

Quote:Original post by sirob
2) Does GraphicsStream::Position take a value in bytes? I wouldn't be surprised if it took an index of the item to set it to, in which case your * 4 would make you go out of bounds.


I'm pretty sure it does since that part is based on the IO.Stream class. See the next point.

Quote:Original post by sirob
Also, you mention it only fails some of the times. What happens when you get no error? Do the results match what you expect it to do?


When I get no error everything appears as it should.

Also I've sort of solved this by setting the textures usage to Usage.Dynamic and the pool to Pool.Default, but I'd like a more "proper" solution. I don't need them to be dynamic since they're only written to when the level loads.
Quote:Original post by Scet
Quote:Original post by sirob
I can see a couple things here:
1) You're not using the pitch returned by lock call. You'll need to use a different overload to have it returned, but it is highly recommended you use the pitch value when writing/reading from textures or surfaces.


But then how would I use it? Add it to GraphicsStream.Position?


You'd use the pitch returned as the width of the surface. DX might return a surface larger than what you requested when you lock, and you have no control over this. The pitch is returned to allow you to skip an entire row on a surface who's width you wouldn't have any other way of knowing. The pitch's minimum value is the width you specify, and would most likely be equal to your surface's width.

As for the actual problem, I can't say I have any ideas. AFAIK, managed textures should be lockable, and shouldn't behave differently. As I said, my only idea is avoiding two locks at once, but considering it works with Default + Dynamic this is now sounding less likely.

Perhaps someone else will have an idea.
Sirob Yes.» - status: Work-O-Rama.

This topic is closed to new replies.

Advertisement