Search code examples
c#.netslimdxsharpdx

Moving from SlimDX to SharpDX - Effects


We have a project that currently uses DirectX11 SlimDX and would like to move it to SharpDX. However, this project uses the Effect framework from SlimDX which I understand is no longer properly supported in DirectX11. However I can't find definitive information about how I should transition the effects.

The effects in use are relatively simple pixels shaders, contained in .fx files.

Should I move away from .fx files? What to? To plain .hlsl files? Or should I use the SharpDX Toolkit? Does this use a different format from .fx files?

I can't find any documentation on this. Is there anyone who has made this transition who could give me some advice, or any documentation on the SharpDX Toolkit effects framework?


Solution

  • The move to SharpDX is pretty simple, there's a couple of changes in naming, and resource description, but apart the fact that it's relatively cumbersome (depending on the size of your code base), there's nothing too complex.

    About effects framework, you have the library SharpDX.Direct3D11.Effects that wraps it, so you have it of course supported. It's pretty much the same as per SlimDX counterpart, so you should not have any major issues moving from it.

    If you want to transition away from fx framework to more plain hlsl, you can keep the same fx file, compilation steps will change, instead on compiling the whole file you need to compile each shader separately.

    So for example, to compile and create a VertexShader:

    CompilationResult result = ShaderBytecode.Compile(content, "VS", "vs_5_0", flags, EffectFlags.None, null, null);
    
    VertexShader shader = new VertexShader(device, result.Bytecode);
    

    Also you need to be careful with all constantbuffers/resource registers, it's generally good to set them explicitely, for example:

    cbuffer cbData : register(b0)
    {
    float4x4 tW;
        float4x4 tColor;
    float4 cAmb;
    };
    

    You of course don't have anymore all the EffectVariable, Get by name/semantic, so instead you need to map your cBuffer to a struct in c# (you can also use datastream directly), and create Constant buffer resources.

    [StructLayout(LayoutKind.Sequential,Pack=16)]
    public struct cbData
    {
        public Matrix tW;
        public Matrix tColor;
        public Vector4 cAmb;
    }
    
    BufferDescription bd = new BufferDescription()
    {
       BindFlags = BindFlags.ConstantBuffer,
       CpuAccessFlags = CpuAccessFlags.Write,
       OptionFlags = ResourceOptionFlags.None,
       SizeInBytes = 144, //Matches the struct
       Usage = ResourceUsage.Dynamic
    };
    
    var cbuffer = new SharpDX.Direct3D11.Buffer(device, bd);
    

    Use either UpdateSubResource or MapSubresource to update data, and deviceContext.VertexShader.SetConstantBuffer to bind to pipeline.

    If you need to inspect shader with reflection, this is done this way (please note that's actually what the effects framework does, it's just a layer on top of d3dcompiler):

    ShaderReflection refl = new ShaderReflection(result.Bytecode);
    

    You then need to set up all API calls manually (which is what Effects does for you when you call EffectPass.Apply ).

    Also since you compile shaders individually, there is no more layout validation between stages (effects compiler giving you : No valid VertexShader-PixelShader combination....). So you need to be careful setting your pipeline with non matching shaders (you can use reflection data to validate manually, or watch a black screen with debug runtime spamming your output window in visual studio).

    So transitioning can be a bit tedious, but can also be beneficial since it's easier to minimize pipeline state changes (In my use case this is not a concern, so effects framework does just fine, but if you have a high number of draw calls that can become significant).