Sign in to follow this  
roastedamoeba

Setting Parameters in Effects

Recommended Posts

This question is specific to Managed Direct3D, as it wouldn't be an issue with native Direct3D. I have a structure (well, struct in C#) that I want to set as a parameter to a D3D Effect. I know it's possible, because I have some code in C++ that does exactly that. Normally, you'd set a parameter like this:
int nValue = 1;
myEffect.SetValue(EffectHandle parameter, nValue);

However, for non-integral types it becomes more complicated. There's only two overloads of SetValue that look like they could take a structure:
Effect.SetValue(EffectHandle parameter, GraphicsStream data);
Effect.SetValue(EffectHandle parameter, void* data, int dataSize);

The problem is, I have no idea how to get my struct into a GraphicsStream, or converted to a void*. I've messed around with unsafe pointers, the System.Runtime.InteropServices.Marshal class, etc., but can't get anything to work. Can anyone help? Any assistance would be much appreciated... Tim

Share this post


Link to post
Share on other sites
Never mind, I've solved it - in case anybody is interested, here's how to do it (note that the object passed in must be a struct, not a class.


using System.Runtime.InteropServices;

public unsafe void SetStructure(string sParameterName, object pObject)
{
int nSize = Marshal.SizeOf(pObject);
IntPtr pUnmanagedPointer = Marshal.AllocHGlobal(nSize);

Marshal.StructureToPtr(pObject, pUnmanagedPointer, true);

m_pEffect.SetValue(GetEffectHandle(sParameterName), pUnmanagedPointer.ToPointer(), nSize);

Marshal.FreeHGlobal(pUnmanagedPointer);
}

Share this post


Link to post
Share on other sites
Neat! I was wondering how I would go about integrating shaders with my C# based DX engine and since I have a material (different from DX) structure ...

Thanks for sharing!

Share this post


Link to post
Share on other sites
Interesting. That kinda sucks that you can't simply cast to void*. Fortunately for begginners, C# doesn't really deal much with pointers and memory managment. Unfortunately for the advanced developers, it would have come in handy in places like this.

Share this post


Link to post
Share on other sites
Indeed. Although it's not really that difficult to get a pointer (once you know how to do it, anyway), and in my (c#-biased) opinion the ease of memory management makes it worth it...

Anyway, there may well be a better method than the one above, but it works, so I'm happy for the moment :)

Tim

Share this post


Link to post
Share on other sites
Quote:
Original post by circlesoft
That kinda sucks that you can't simply cast to void*.


I think you can so long as it is a value type.

Did you try something like this?

unsafe{
m_pEffect.SetValue(sParameterName, (void*)&pObject, nSize);
}

Note that EffectHandles are implicitly cast from strings and the reason that you would use GetParameter to pre fetch a handle is to avoid having the effect look it up every time you set it. Still it is probably going to be hard to make a faster name lookup method than that within the Effect classes. In other words use the string names when you call SetValue unless you know for sure you are making an optimization.

Share this post


Link to post
Share on other sites
Hi turnpast,

Thanks for your comments :)

I did used to pass in the parameter name as a string, but I've since changed it (I store the EffectHandles in a Hashtable, keyed by parameter name). I don't know which is faster as I haven't profiled it yet, but gut feeling is my Hashtable is faster than passing in strings. I've used Reflector and I can't see that the Direct3D code is doing any caching of EffectHandles.

I did also try the code you suggested before I came up with my solution, but the compiler throws this error:

Cannot take the address or size of a variable of a managed type ('object')

The compiler says that even if you pass it a struct (i.e. not boxed into an object).

Tim

Share this post


Link to post
Share on other sites
Quote:
Original post by roastedamoeba
Cannot take the address or size of a variable of a managed type ('object')

The compiler says that even if you pass it a struct (i.e. not boxed into an object).


Yes, you can only take the address of value types (ie. structs) in that way. That said, if you are passing structures into your effects you should probably be using structs and even explicitly laying out the varaibles in your struct with the StructLayout attribute. (then you know the size too).

The other way to access the members of structs in your effect is to pass the EffectHandle of the sturct as the first argument to GetParameter and the name of the member as the second. When you are accessing an array you can also use GetParameterElement to get a handle on a single element of the array.

//Struct:
EffectHandle structHandle = effect.GetParameter(null,"someStruct");
EffectHandle memberHandle = effect.GetParameter(structHandle,"someMember");
//Array:
EffectHandle arrayHandle = effect.GetParameter(null,"someArray");
EffectHandle thirdElementHandle = effect.GetParameterElement(structHandle,2);


One more thing:
Microsoft.DirectX.DXHelp several methods to 'help' with this stuff: CopyObjectDataToPointer, CopyPointerDataToObject, GetObjectSize and GetTypeSize.

Share this post


Link to post
Share on other sites
Quote:
Original post by turnpast
Yes, you can only take the address of value types (ie. structs) in that way. That said, if you are passing structures into your effects you should probably be using structs and even explicitly laying out the varaibles in your struct with the StructLayout attribute. (then you know the size too).


Yes, that's what I meant - you can't take the address of structs, the compiler throws an error. I think you have to use the "fixed" keyword.

I am passing a struct into my effect, and it seems to be working without the StructLayout attribute.

Quote:
Original post by turnpast
The other way to access the members of structs in your effect is to pass the EffectHandle of the sturct as the first argument to GetParameter and the name of the member as the second. When you are accessing an array you can also use GetParameterElement to get a handle on a single element of the array.


True, but the whole reason I'm using a struct is so I don't need to pass each member in individually.

Quote:
Original post by turnpast
One more thing:
Microsoft.DirectX.DXHelp several methods to 'help' with this stuff: CopyObjectDataToPointer, CopyPointerDataToObject, GetObjectSize and GetTypeSize.


Interesting - didn't know about those, thank you :) The documentation for CopyObjectDataToPointer says that it copies strings and arrays of strings, nothing about structs, but I haven't tried it.

Share this post


Link to post
Share on other sites

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