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