MikePopoloski / SharpBgfx

C# bindings for the bgfx graphics library
MIT License
169 stars 32 forks source link

SharpBgfx makes ABI assumptions about struct-by-value params/return vals #34

Closed vvuk closed 2 years ago

vvuk commented 5 years ago

The bgfx API has a lot of handle types that are passed as by-value structs, e.g.

typedef struct bgfx_shader_handle_s { uint16_t idx; } bgfx_shader_handle_t;

BGFX_C_API bgfx_program_handle_t bgfx_create_program(bgfx_shader_handle_t _vsh, bgfx_shader_handle_t _fsh, bool _destroyShaders);

SharpBgfx writes the DllImport like this:

        [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern ushort bgfx_create_program (ushort vsh, ushort fsh, [MarshalAs(UnmanagedType.U1)] bool destroyShaders);

This is incorrect -- whether the small struct that fits in a register is passed in the register, or still passed by pointer, is ABI-dependant. In particular, the Emscripten asmjs/wasm ABI always passes by pointer.

vvuk commented 5 years ago

A quick fix is to define:

    public struct Handle {
        public ushort value;

        public Handle(ushort v) => this.value = v;
        public static implicit operator ushort(Handle h) => h.value;
        public static implicit operator Handle(ushort v) => new Handle(v);
    }

in NativeMethods, and make all handle params/returns be of type Handle. With this and the implicit conversions, no other code needs to change (except for one place in Framebuffer.cs, depending on if you change the ushort* to a Handle* in the native method param).