Error Running jextract on d3d12.h

Michael Ennen mike.ennen at gmail.com
Sun Sep 13 01:37:06 UTC 2020


Well, progress of a kind? This crashes the VM instead of not compiling or
throwing an exception:

// IDXGIFactory1** dxgiFactory;
var dxgiFactory = scope.allocate(C_POINTER);
// HRESULT = CreateDXGIFactory1(_uuid(dxgiFactory), &dxgiFactory))
int hresult = dxgi_h.CreateDXGIFactory1(GUID(IID.IID_IDXGIFactory1),
dxgiFactory);
System.out.println("hresult: " + hresult);
var dxgiAdapter = scope.allocate(C_POINTER);
System.out.println("IDXGIFactory1Vtbl byte size: " +
dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize()); //112
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.address());
} catch (Throwable throwable) {
throwable.printStackTrace();
}

On Sat, Sep 12, 2020 at 6:34 PM Michael Ennen <mike.ennen at gmail.com> wrote:

> I think I see why. It's because I am passing in a MemorySegment, which is
> the dxgiAdapter which I initialize thusly:
>
> var dxgiAdapter = scope.allocate(C_POINTER);
>
> I guess I need to make it a MemoryAddress instead.
>
> On Sat, Sep 12, 2020 at 2:25 PM Michael Ennen <mike.ennen at gmail.com>
> wrote:
>
>> 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
>>
>
>
> --
> Michael Ennen
>


-- 
Michael Ennen


More information about the panama-dev mailing list