Hello, I’ve been working on creating some hxcpp externs for several directx libraries for myself and have ran into some small issues surrounding directx’s pointer usage and hxcpp inline function generation.
Since directx is rather pointer heavy I’ve been wrapping my extern classes in ::cpp::Pointer
and pretty much exclusively using inline functions and untyped to make the haxe externs cleaner and easier to use.
Sample ID3D11Device and ID3D11Buffer externs, used in examples later on.
@:unreflective
@:native("::cpp::Pointer<ID3D11Device>")
@:include("d3d11.h")
extern class Device extends IUnknown
{
inline function createBuffer(_description : BufferDescription, _buffer : Buffer) : Int
{
return untyped __cpp__('{0}->ptr->CreateBuffer(&{1}, nullptr, (ID3D11Buffer**)&{2})', this, _description, _buffer);
}
}
@:unreflective
@:native("::cpp::Pointer<ID3D11Buffer>")
@:include("d3d11.h")
extern class Buffer extends IUnknown
{
//
}
This has been working fine for the most part and I’m happy with how nice the haxe externs are to use but I’ve run into a small problem surrounding haxe inline functions and directx functions which take a pointer to a pointer.
Say I have a class and a member variable vertexBuffer
which is of the Buffer extern type and in some function I call device.createBuffer
passing vertexBuffer
as the last argument to create a buffer. Despite that function returning S_OK
(0) vertexBuffer
will still be null instead of an address due to how hxcpp is generating inline functions.
// Haxe
if (device.createBuffer(bufferDesc, vertexBuffer) != 0)
{
throw 'Failed to create vertex buffer';
}
// Generated C++
HXLINE( 245) cpp::Pointer<ID3D11Device> _this9 = this->device;
HXDLIN( 245) cpp::Pointer<ID3D11Buffer> _buffer = this->vertexBuffer;
HXDLIN( 245) if (hx::IsNotEq( _this9->ptr->CreateBuffer(&bufferDesc, nullptr, (ID3D11Buffer**)&_buffer),0 )) {
HXLINE( 247) HX_STACK_DO_THROW(HX_("Failed to create vertex buffer",9a,75,75,96));
}
It seems like hxcpp creates local variables for inline functions arguments and then uses them. So in this case _buffer
is assigned to the member variable vertexBuffer
and that is used instead of using vertexBuffer
directly. Since the directx createBuffer function takes a pointer to a pointer that temporary pointer variable will contains the address of the created buffer while vertexBuffer
remains null.
I can work around this creating my own temporary pointer variable on the haxe side and reassign the member pointer afterwards and that seems to satisfy hxcpp for the inline function argument, but this makes the code messier and the externs harder to work with.
// With temporary variable pointer
// Haxe
var tmpVtxBuffer : Buffer = null;
if (device.createBuffer(bufferDesc, tmpVtxBuffer) != 0)
{
throw 'Failed to create vertex buffer';
}
vertexBuffer = tmpVtxBuffer;
// Generated C++
HXLINE( 244) cpp::Pointer<ID3D11Buffer> tmpVtxBuffer = null();
HXLINE( 245) cpp::Pointer<ID3D11Device> _this9 = this->device;
HXDLIN( 245) if (hx::IsNotEq( _this9->ptr->CreateBuffer(&bufferDesc, nullptr, (ID3D11Buffer**)&tmpVtxBuffer),0 )) {
HXLINE( 247) HX_STACK_DO_THROW(HX_("Failed to create vertex buffer",9a,75,75,96));
}
HXLINE( 249) this->vertexBuffer = tmpVtxBuffer;
Doing the above everything works fine and vertexBuffer
has the buffer address but I’d rather not have to create extra code for this work around. Directx has quite a few of these pointer to a pointer functions for creating resources so if anyone has any advice on how I can change the externs to avoid this it’d be greatly appreciated.
Thanks, and sorry for the long post.