Marshalling C# Structs into DX11 cbuffers

泄露秘密 提交于 2019-12-10 21:44:55

问题


I'm having some issues with (i think) the packing of my structure in C# and passing them through to cbuffers i have registered in HLSL. When i pack my struct in one manner the information seems to be able to pass to the shader:

[StructLayout(LayoutKind.Explicit, Size = 16)]
internal struct TestStruct
{
    [FieldOffset(0)]
    public Vector3 mEyePosition;

    [FieldOffset(12)]
    public int type;
}

When i create this struct and set it as my constant buffer in C# it seems to work just fine. I get what colours returned that i expect:

cbuffer PerFrame : register(b0)
{
    Vector3 eyePos;
    int type;
}

float3 GetColour()
{
    float3 returnColour = float(0.0f, 0.0f, 0.0f);

    switch(type)
    {
        case 0:
            returnColour = float3(1.0f, 0.0f, 0.0f);
            break;
        case 1:
            returnColour = float3(0.0f, 1.0f, 0.0f);
            break;
        case 2:
            returnColour = float3(0.0f, 0.0f, 1.0f);
            break;
    }

    return returnColour;
}

But when i change the structure to be a struct using another struct it does seem to set properly. Note that internal struct is going to be containing extra information in it, but i was trying to simplify it as much as possible for now:

[StructLayout(Layout.Explicit, Size = 16)] //Note this is 16 because HLSL packs in 4 float 'chunks'
internal struct InternalTestStruct
{
    [FieldOffset(0)]
    public int type;
}

[StructLayout(LayoutKind.Explicit, Size = 32)]
internal struct TestStruct
{
    [FieldOffset(0)]
    public Vector3 mEyePosition;

    //Missing 4 bytes here for correct packing.

    [FieldOffset(16)]
    public InternalTestStruct internal;
}

And in HLSL

struct InternalType
{
    int type;
}

cbuffer PerFrame : register(b0)
{
    Vector3 eyePos;
    InternalType internalStruct;
}

float3 GetColour()
{
    float3 returnColour = float(0.0f, 0.0f, 0.0f);

    switch(internaltype.type)
    {
        case 0:
            returnColour = float3(1.0f, 0.0f, 0.0f);
            break;
        case 1:
            returnColour = float3(0.0f, 1.0f, 0.0f);
            break;
        case 2:
            returnColour = float3(0.0f, 0.0f, 1.0f);
            break;
    }

    return returnColour;
}

Do you think there is a problem in the way i am packing my structs? Or could the issue be elsewhere, i only think it is my packing because i can get the first example to work when i set the constant buffer with a TestStruct, but as soon as i expand it to include the InternalTestStruct it doesn't seem to work.

Any help would be great.

Thanks in advance.


回答1:


When you use:

struct InternalType
{
    int type;
}

cbuffer PerFrame : register(b0)
{
    float3 eyePos;
    InternalType internalStruct;
} 

since InternalType is of size 4 it will pack into the layout of 16, so it's exactly the same as if you were just using an int.

To match the second c# structure using InternalTestStruct, you'd need to do:

cbuffer PerFrame : register(b0)
{
    float3 eyePos;
    int dummy; //Here you need to force the padding
    InternalType internalStruct;
} 

If you change internaltype to a size larger than one the padding will then become automatic (but it's always nice to keep it explicit).



来源:https://stackoverflow.com/questions/8145279/marshalling-c-sharp-structs-into-dx11-cbuffers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!