Error Running jextract on d3d12.h
Michael Ennen
mike.ennen at gmail.com
Sat Sep 12 21:25:37 UTC 2020
Thanks so much Ty. That's super helpful. I think I was able to make quite a
bit of progress:
var dxgiAdapter = scope.allocate(C_POINTER);
System.out.println("IDXGIFactory1Vtbl byte size: " +
dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
MemorySegment segment =
MemorySegment.allocateNative(dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
MemoryAddress address = segment.address().addOffset(64);
FunctionDescriptor functionDescriptor = FunctionDescriptor.of(C_INT, C_INT,
C_POINTER);
MethodType methodType = MethodType.methodType(int.class, int.class,
MemoryAddress.class);
MethodHandle methodHandle = getSystemLinker().downcallHandle(address,
methodType, functionDescriptor);
try {
methodHandle.invokeWithArguments(0, dxgiAdapter);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Note that the EnumAdapters1 function signature is actually:
HRESULT EnumAdapters1(
UINT Adapter,
IDXGIAdapter1 **ppAdapter
);
So that's why I went with:
FunctionDescriptor functionDescriptor = FunctionDescriptor.of(C_INT, C_INT,
C_POINTER);
and then
methodHandle.invokeWithArguments(0, dxgiAdapter);
I did some fancy stuff as per your suggestion which I feel should be
getting the address of the EumAdapters1 function
pointer (basically start at the base address of the struct and then move 64
bytes past, which should be the 8th function
pointer which in this case is EnumAdapters1).
I do get the following exception on invoking the method handle, though:
hresult: 0
factory: MemorySegment{ id=0x3898fd8a limit: 8 }
IDXGIFactory1Vtbl byte size: 112
java.lang.ClassCastException: Cannot cast
jdk.internal.foreign.NativeMemorySegmentImpl to
jdk.incubator.foreign.MemoryAddress
at java.base/java.lang.Class.cast(Class.java:3816)
at
java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733)
at com.dx12.DX12.main(DX12.java:91)
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at
jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:415)
at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
at
jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
vh: VarHandle[varType=jdk.incubator.foreign.MemoryAddress, coord=[interface
jdk.incubator.foreign.MemorySegment]]
Any more assistance would be greatly appreciate but undeserved :).
On Sat, Sep 12, 2020 at 1:41 AM Ty Young <youngty1997 at gmail.com> wrote:
> Not a JDK developer, but if you want to do this by hand(aka no
> jextract), I had to do this for NVAPI which obfuscates function pointers
> using keys, e.g.:
>
>
> nvapi_h.nvapi_QueryInterface(0x0150e828);
>
>
> where "0x0150e828" is the "NvAPI_Initialize" function key as per the
> Open Source headers Nvidia released sometime ago.
>
>
> The only difference is that, since the function pointer is in a struct,
> you need to get the segment in the struct containing the function
> pointer(see "slice" MemorySegment method) and actually read from it
> using a VarHandle. You then take that MemoryAddress, with a
> FunctionDescriptor and MethodType, and create a MethodHandle. For
> reference, this my working code("NativeFunction" and "NativeTypes" do
> not exist in Panama, those are mine but they dont matter) for the
> NvAPI_Initalize API:
>
>
> public class NvAPI_Initialize implements NativeFunction
> {
> private final MemoryAddress address;
> private final FunctionDescriptor descriptor;
> private final MethodType type;
>
> private final MethodHandle handle;
>
> public NvAPI_Initialize() throws NoSuchMethodException, Throwable
> {
> this.address = nvapi_h.nvapi_QueryInterface(0x0150e828);
>
> this.descriptor = FunctionDescriptor.of(NativeTypes.INT);
>
> this.type = MethodType.methodType(int.class);
>
> this.handle =
> CSupport.getSystemLinker().downcallHandle(this.address, this.type,
> this.descriptor);
> }
>
> // etc
>
> }
>
>
> It looks like in your case the FunctionDescriptor would be:
>
>
> this.descriptor = FunctionDescriptor.of(CSupport.C_POINTER,
> CSupport.C_INT, CSupport.C_POINTER);
>
>
> for MethodType:
>
>
> MethodType.methodType(MemoryAddress.class, int.class, MemoryAddress.class);
>
>
> where the first argument takes in a IDXGIFactory, the second an unsigned
> int, and the third a pointer to what looks like an opaque device that
> you pass to other functions.
>
>
> If you haven't already, it might help to make bindings with a smaller,
> less complicated library just to get a feel with how things work under
> the hood.
>
>
> Hope this helps.
>
>
> On 9/12/20 2:23 AM, Michael Ennen wrote:
> > Looking into this a bit further I think I chose a really bad library to
> > start with as the function I need to call, EnumAdapters, is inside
> > some type of "VTbl" struct that is trying to emulate a C++ class with
> > virtual functions. What jextract is returning is most likely *correct*
> > but in this case so complicated because of how it is laid out in C. It is
> > not clear at all how to grab the EnumAdapters function from
> > this mess, and it is probably above my head.
> >
> > EXTERN_C const IID IID_IDXGIFactory;
> >
> > #if defined(__cplusplus) && !defined(CINTERFACE)
> >
> > MIDL_INTERFACE("7b7166ec-21c7-44ae-b21a-c9ae321ae369")
> > IDXGIFactory : public IDXGIObject
> > {
> > public:
> > virtual HRESULT STDMETHODCALLTYPE EnumAdapters(
> > /* [in] */ UINT Adapter,
> > /* [annotation][out] */
> > _COM_Outptr_ IDXGIAdapter **ppAdapter) = 0;
> >
> > virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
> > HWND WindowHandle,
> > UINT Flags) = 0;
> >
> > virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation(
> > /* [annotation][out] */
> > _Out_ HWND *pWindowHandle) = 0;
> >
> > virtual HRESULT STDMETHODCALLTYPE CreateSwapChain(
> > /* [annotation][in] */
> > _In_ IUnknown *pDevice,
> > /* [annotation][in] */
> > _In_ DXGI_SWAP_CHAIN_DESC *pDesc,
> > /* [annotation][out] */
> > _COM_Outptr_ IDXGISwapChain **ppSwapChain) = 0;
> >
> > virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
> > /* [in] */ HMODULE Module,
> > /* [annotation][out] */
> > _COM_Outptr_ IDXGIAdapter **ppAdapter) = 0;
> >
> > };
> >
> >
> > #else /* C style interface */
> >
> > typedef struct IDXGIFactoryVtbl
> > {
> > BEGIN_INTERFACE
> >
> > HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
> > IDXGIFactory * This,
> > /* [in] */ REFIID riid,
> > /* [annotation][iid_is][out] */
> > _COM_Outptr_ void **ppvObject);
> >
> > ULONG ( STDMETHODCALLTYPE *AddRef )(
> > IDXGIFactory * This);
> >
> > ULONG ( STDMETHODCALLTYPE *Release )(
> > IDXGIFactory * This);
> >
> > HRESULT ( STDMETHODCALLTYPE *SetPrivateData )(
> > IDXGIFactory * This,
> > /* [annotation][in] */
> > _In_ REFGUID Name,
> > /* [in] */ UINT DataSize,
> > /* [annotation][in] */
> > _In_reads_bytes_(DataSize) const void *pData);
> >
> > HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )(
> > IDXGIFactory * This,
> > /* [annotation][in] */
> > _In_ REFGUID Name,
> > /* [annotation][in] */
> > _In_opt_ const IUnknown *pUnknown);
> >
> > HRESULT ( STDMETHODCALLTYPE *GetPrivateData )(
> > IDXGIFactory * This,
> > /* [annotation][in] */
> > _In_ REFGUID Name,
> > /* [annotation][out][in] */
> > _Inout_ UINT *pDataSize,
> > /* [annotation][out] */
> > _Out_writes_bytes_(*pDataSize) void *pData);
> >
> > HRESULT ( STDMETHODCALLTYPE *GetParent )(
> > IDXGIFactory * This,
> > /* [annotation][in] */
> > _In_ REFIID riid,
> > /* [annotation][retval][out] */
> > _COM_Outptr_ void **ppParent);
> >
> > HRESULT ( STDMETHODCALLTYPE *EnumAdapters )(
> > IDXGIFactory * This,
> > /* [in] */ UINT Adapter,
> > /* [annotation][out] */
> > _COM_Outptr_ IDXGIAdapter **ppAdapter);
> >
> > HRESULT ( STDMETHODCALLTYPE *MakeWindowAssociation )(
> > IDXGIFactory * This,
> > HWND WindowHandle,
> > UINT Flags);
> >
> > HRESULT ( STDMETHODCALLTYPE *GetWindowAssociation )(
> > IDXGIFactory * This,
> > /* [annotation][out] */
> > _Out_ HWND *pWindowHandle);
> >
> > HRESULT ( STDMETHODCALLTYPE *CreateSwapChain )(
> > IDXGIFactory * This,
> > /* [annotation][in] */
> > _In_ IUnknown *pDevice,
> > /* [annotation][in] */
> > _In_ DXGI_SWAP_CHAIN_DESC *pDesc,
> > /* [annotation][out] */
> > _COM_Outptr_ IDXGISwapChain **ppSwapChain);
> >
> > HRESULT ( STDMETHODCALLTYPE *CreateSoftwareAdapter )(
> > IDXGIFactory * This,
> > /* [in] */ HMODULE Module,
> > /* [annotation][out] */
> > _COM_Outptr_ IDXGIAdapter **ppAdapter);
> >
> > END_INTERFACE
> > } IDXGIFactoryVtbl;
> >
> > interface IDXGIFactory
> > {
> > CONST_VTBL struct IDXGIFactoryVtbl *lpVtbl;
> > };
> >
> >
>
--
Michael Ennen
More information about the panama-dev
mailing list