Jump to content
  • Advertisement
Sign in to follow this  
tool_2046

Locking a Surface using SlimDX

This topic is 3872 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 am working on a level editor using C#/SlimDX and I'd like to render previews of models for use on various GUI elements. To do this, I am trying to render the scene to a surface and then copy the surface to a Bitmap. Unfortunately, whenever I attempt to read from the surface after locking it, I get a System.NotSupportedException with the following message:
Stream size unknown; cannot query length.
This seems to happen regardless of what memory pool I use, what usage flag I choose, what lock flags I use, and whether I create a surface using Surface.CreateRenderTarget, Surface.CreateOffscreenPlain, or get the surface from a texture. The following code will generate generate the exception:
Format format = Format.X8R8G8B8;
Surface test = Surface.CreateOffscreenPlain(device, width, height, format, Pool.Default);
LockedRect rect = t.LockRectangle(0, LockFlags.None);
long l = rect.Data.Length; // Throws System.NotSupportException.
test.UnlockRectangle();

I'm sure I'm doing something foolish here, but googling has failed me, I can't find anything on the SlimDX website that seems relevant to the problem and randomly fiddling with parameters has (not surprisingly) not helped. Any idea what I'm doing wrong? Thanks for your time!

Share this post


Link to post
Share on other sites
Advertisement
DataStream used to allow for buffers of unknown size (that is, when we locked the resource internally to return a DataStream to the user, if we didn't immediately have the size available we simply said "we don't know how big this resource is," because in many cases that information is not actually available directly at the lock site). Obviously, when the buffer's size is not known, we cannot support seeking from the end of the buffer or querying for the buffer size.

In the recent SVN builds and the upcoming March release, DataStream can no longer accept an unknown size and will throw if we happen to try to construct one that way - since this does not appear to be that particular exception, I gather you are using an older build?

Can you post the code you're using to lock and read the buffer? Something is indirectly or directly asking the buffer for its length, and either your build is old enough that we still allowed unknown lengths or we missed a spot where we let the "unknown size" sentinel (0) slip through the constructor without throwing.

EDIT: Oh, either I missed your code the first time or you edited while I was replying... but yes, you can't query the length because the surface isn't reporting its size to the DataStream. Getting the byte sizes of locked surfaces is a bit annoying, that's why we didn't do it originally. I'd advise upgrading to a SVN build that's more recent or waiting for the March release... it should be out very soon. If that isn't an option for you, you can examine the source code to the Direct3D9 Surface::LockRectangle method using Google Code's code browser -- it should show you what we do in the new builds to compute the size, and you can replicate that.

Upgrading may be easier, though.

Share this post


Link to post
Share on other sites
Thank you, I really appreciate your help. I suppose there isn't a rush to get this particular feature working, so I can wait for the March release.

Having said all that, I'm still somewhat confused. I don't need the size of the DataStream, but any of the Read calls (ReadByte, Read<T>, etc) seem to fail also with the same exception. I tried the following code without success:

while (rect.Data.CanRead)
{
int b = rect.Data.ReadByte();
}


What was the accepted technique for reading the data from a stream with an unknown length? (I'm currently using the November 07 release). Thanks again for your help!

Share this post


Link to post
Share on other sites
Well, I can tell you right now that while loop isn't going to do what you want. CanRead (CanWrite, et cetera) are properties that reflect the read-write permissions of the locked buffer (e.g., whether or not the CPU side code is allowed to read from or write to the buffer at all). It's not an EOF-like property, so that loop will either never execute or execute forever, depending.

DataStream doesn't have a ReadByte method itself, it inherits that from Stream. The default implementation of ReadByte, in Stream, is to create a new single-element array and call the Read overload that takes a byte array:

int DataStream::Read( array<Byte>^ buffer, int offset, int count )
{
if( !m_CanRead )
throw gcnew NotSupportedException();
if( buffer == nullptr )
throw gcnew ArgumentNullException( "buffer" );
if( offset < 0 || offset >= buffer->Length )
throw gcnew ArgumentOutOfRangeException( "offset" );
if( count < 0 || offset + count > buffer->Length )
throw gcnew ArgumentOutOfRangeException( "count" );


int actualCount = count;
if( Length > 0 )
actualCount = min( (int) (Length - m_Position), count );

pin_ptr<Byte> pinnedBuffer = &buffer[offset];
memcpy( pinnedBuffer, m_Buffer + m_Position, actualCount );

m_Position += actualCount;
return count;
}

(this is the code from the Nov07 tag in SVN).

So it looks like what's going on here is that we're calling Length inside Read (in the if() beneath the declaration of actualCount), which we should not be doing.

You said you're using C#, but I don't see the overload for LockRectangle that your code suggests you're calling. I see one taking just the flags and one taking a Rectangle.

Unfortunately, all the Read methods are checking Length in the Nov07 release, and all the Surface methods that lock do so with a 0 size. I don't see a clean workaround for you here, I'm afraid. The bug should be fixed in the SVN builds; you may want to try checking it out and building it. If nothing else it will give you a head start on coping with some of the interface changes we've made for the upcoming release.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!