Sign in to follow this  

SlimDX: Strange behavior on VertexBuffer/IndexBuffer locks

This topic is 3730 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've some strange behavior when using dynamic buffers to display quad's. I follow the usual steps: Create dynamic buffers, lock, fill, unlock, draw, but the quads I was drawing was flickering madly. After going over all of my code I ended up in the buffer locking. I used the following to lock:
mVertexBuffer.Lock(offset * mStride, lf)

This seemed fine, but then I saw in the SlimDX code that I could also pass a size along to Lock. So I changed the code to
mVertexBuffer.Lock(offset * mStride, count * mStride, lf)

and suddenly all the flickering stopped, and the quad's was rendered perfectly. In SlimDX Lock is as follows:
DataStream^ VertexBuffer::Lock( int offset, int size, LockFlags flags )
{
	void* lockedPtr;
	HRESULT hr = VbPointer->Lock( offset, size, &lockedPtr, (DWORD) flags );
	GraphicsException::CheckHResult( hr );
		
	int lockedSize = size == 0 ? SizeInBytes : size;
		
	bool readOnly = (flags & LockFlags::ReadOnly) == LockFlags::ReadOnly;
	DataStream^ stream = gcnew DataStream( lockedPtr, lockedSize, true, !readOnly );
	return stream;
}
	
DataStream^ VertexBuffer::Lock( int offset, LockFlags flags )
{
	return Lock( offset, 0, flags );
}

but after looking in the DX documenation I found the following under IDirect3DVertexBuffer9::Lock:
Quote:
OffsetToLock [in] Offset into the vertex data to lock, in bytes. To lock the entire vertex buffer, specify 0 for both parameters, SizeToLock and OffsetToLock. SizeToLock [in] Size of the vertex data to lock, in bytes. To lock the entire vertex buffer, specify 0 for both parameters, SizeToLock and OffsetToLock.
It seems having OffsetToLock != 0 and SizeToLock == 0 will give an incorrect behavior. To correct this I think Lock in SlimDX should be changed to something like:
DataStream^ VertexBuffer::Lock( int offset, int size, LockFlags flags )
{
	int lockedSize = size == 0 ? SizeInBytes - offset : size;
		
	void* lockedPtr;
	HRESULT hr = VbPointer->Lock( offset, lockedSize, &lockedPtr, (DWORD) flags );
	GraphicsException::CheckHResult( hr );
		
	bool readOnly = (flags & LockFlags::ReadOnly) == LockFlags::ReadOnly;
	DataStream^ stream = gcnew DataStream( lockedPtr, lockedSize, true, !readOnly );
	return stream;
}

and equivalent for IndexBuffer.

Share this post


Link to post
Share on other sites
That function is fine. The problem is that the overload you tried to use initially was written in such a way that it will never provide D3D with usable data. I'm not sure why that overload is in there; it may have been put in early on when functions were still being pulled verbatim from MDX. It's not a particularly useful function, and your fix is broken because it mutates the parameters being submitted to D3D.

In any case, after some discussion we've decided to ditch the two argument overload outright. Just use the offset, size, flags version.

Share this post


Link to post
Share on other sites
You don't say :)
Which is a good reason to add an assert( offset == 0 || size > 0 ) or throw an ArgumentException. But I can live with it, removing the invalid Lock method worked for me.

Share this post


Link to post
Share on other sites
The point is that those limitations on the parameters are D3D's business. We just exist to expose D3D to you and make your life a bit more comfy in the process. Not only that, there's no guarantee (past or future) that those restrictions on the parameters will continue to hold. And lastly, for us to double validate everything that gets passed down to D3D would be a large amount of effort for basically no gain.

My advice? Do what any reasonable D3D developer should be doing, and run with the Debug runtimes instead of retail. That way, D3D will be inclined to tell you these things and is much more likely to return an error code rather than a success code. That way, you'll get a nice loud exception out of SlimDX whining that you screwed up, and a nice little comment in the debug output about what you did wrong.

Share this post


Link to post
Share on other sites
We haven't really been in the business of validating most parameters any more strictly than the underlying API does, beyond null pointers and any constraints we impose in addition to the underlying API's (such as the "read/write" control over the DataStream object).

This is basically a maintaince and performance cost issue. D3D itself provides suitable validation for a large measure of invalid scenarios via the debug layer, and there's not a lot of motivation for us to simply layer those same checks on top. Additionally, we're more tolerant to changes in the restrictions this way, because we allow the underlying API to handle what the underlying API handles best -- it's own business.

D3D itself is not in the business of holding the programmers hand too much, and our API is designed to be a relatively thin wrapper around it (thus the name), so any additional sanity checking the user wants to do is theretheir problem.

Share this post


Link to post
Share on other sites

This topic is 3730 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this