Error Running jextract on d3d12.h

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Sep 15 10:12:52 UTC 2020


Hi Michael,
You are trying to put a fairly complex example together using the 
foreign API so (1) thanks for sticking with it and (2) there's no harm 
in asking :-)

Again, big disclaimer - I'm not on Windows, so I can't test it out - 
here are some comments from eyeballing your code (although, I can't see 
anything particularly wrong). The one thing I initially focussed on was 
this:

var ppQueue = ID3D12CommandQueue.allocatePointer(scope);

This will allocate a 64-bit long memory segment (enough to contain a 
pointer). But the contents will be blank. But I think this is ok, as the 
API is probably meant to fill in the pointer to the newly allocated 
command queue area (e.g. output parameter idiom).

Another thing I noticed is that you do things like:

> MemorySegment pQueueDesc = D3D12_COMMAND_QUEUE_DESC.allocate(scope);
> MemorySegment queueDesc = asSegment(pQueueDesc.address(), 
> D3D12_COMMAND_QUEUE_DESC.$LAYOUT()); // <--------
> D3D12_COMMAND_QUEUE_DESC.Type$set(queueDesc, 
> D3D12_COMMAND_LIST_TYPE_DIRECT());
> D3D12_COMMAND_QUEUE_DESC.Flags$set(queueDesc, 
> D3D12_COMMAND_QUEUE_FLAG_NONE());
>

I find the second instruction above redundant here. You already have a 
fully readable/writable segment for the struct, you don't need to go to 
the extra jump of re-creating another segment from its address. You can 
just remove that second line and just use pQueueDesc in the two set 
operations. In other words, you should only use `asSegment` if you get a 
MemoryAddress from the library, but you want to turn it into a memory 
segment with certain known size (so that you can read and write from it).


Looking at the GUID function, I also see some issues:

> MemorySegment segment = MemorySegment.allocateNative(GUID.map(l -> 
> ((SequenceLayout) l).withElementCount(8),
> MemoryLayout.PathElement.groupElement("Data4")));
>
>
This doesn't seem to do anything - the layout you start with already has 
a sequence layout with 8 elements in "Data4", so you are just replacing 
that sequence layout with another identical one. That said, this is just 
a stylistic issue, the main logic of the code seems to be correct in 
initializing the contents of the segment (you could use, if you wanted a 
bulk copy to transfer the byte array into "Data4" directly, but that's 
not necessary to get correctness - can be improved later).


Another Java-style comment - you have an Enum defining various IIDs - 
and then you have a unique mapping between an IID and a segment. I 
wonder if the MemorySegment could become a field of the IID enum - so 
that you don't even need the map.


That said, I can't find anything obviously "wrong" with your usage of 
this DX12 API - I've gone back and forth between code and API docs 
several times to check the various structures and pointers you pass, but 
it all looks ok. Are you 100% sure that the crash happens in the 
invokeExact to the CreateCommandQueue? That could suggest one of the 
following:

1) the descriptor you use for linking the function is wrong (e.g. wrong 
argument arity, types) - that doesn't seem to be the case
2) the arguments you are passing are wrong (e.g. unitialized 
args/pointers) - again, this doesn't seem to be the case
3) the function pointer itself being linked is wrong - this I have no 
way to verify

I think it would help to get "crash log" from the VM; that will contain 
extra stack information, such as what exactly the thread was doing when 
the VM crashed - this could tell us for instance if the crash occurred 
inside the dx12 library, or if we didn't even get there - which would 
suggest that the function pointer to CreateCommandQueue is wrong somehow.


I hope this helps a bit. I'm sure we're close.

Cheers
Maurizio





On 15/09/2020 00:05, Michael Ennen wrote:
> At this point I may be beating a dead horse and should be able to 
> figure this out from the awesome example you provided but
> in the case of using "invokeExact" on a MethodHandle, how can one, in 
> that case, send a GUID as an argument?
>
> That is for a global function it was done thusly:
>
> checkResult(dxgi_h.CreateDXGIFactory1(GUID(IID.IID_IDXGIFactory1), 
> ppDxgiFactory));
>
> In the case of "invokeExact" it needs a MemoryAddress so I figured it 
> would just be:
>
>      checkResult((int) 
> MH_ID3D12Device_CreateCommandQueue.invokeExact(pQueueDesc.address(),GUID(IID.IID_ID3D12CommandQueue).address(), 
> ppQueue.address()));
>
> But I am getting an access violation.
>
> I am trying to extend the example to create an ID3D12Device and 
> ID3D12CommandQueue thusly:
>
> //D3D12CreateDevice$MH()
> // ID3D12Device** d3d12Device;
> var ppDevice = ID3D12Device.allocatePointer(scope);
>
> // D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, 
> IID_PPV_ARGS(&ppDevice))
> checkResult(D3D12CreateDevice(pAdapter, (int) 45056L, 
> GUID(IID.IID_ID3D12Device), ppDevice));
> // ID3D12Device*
> MemorySegment pDevice = asSegment(MemoryAccess.getAddress(ppDevice), 
> ID3D12Device.$LAYOUT());
>
> // (This)->lpVtbl
> MemorySegment deviceVtbl = asSegment(ID3D12Device.lpVtbl$get(pDevice), 
> ID3D12DeviceVtbl.$LAYOUT());
>
> // lpVtbl->CreateCommandQueue
> MemoryAddress addrCreateCommandQueue = 
> ID3D12DeviceVtbl.CreateCommandQueue$get(deviceVtbl);
>
> // D3D12_COMMAND_QUEUE_DESC queueDesc = {};
> // queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
> // queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
> MemorySegment pQueueDesc =  D3D12_COMMAND_QUEUE_DESC.allocate(scope);
> MemorySegment queueDesc = asSegment(pQueueDesc.address(), 
> D3D12_COMMAND_QUEUE_DESC.$LAYOUT());
> D3D12_COMMAND_QUEUE_DESC.Type$set(queueDesc, 
> D3D12_COMMAND_LIST_TYPE_DIRECT());
> D3D12_COMMAND_QUEUE_DESC.Flags$set(queueDesc, 
> D3D12_COMMAND_QUEUE_FLAG_NONE());
>
> // link the pointer
> MethodHandle MH_ID3D12Device_CreateCommandQueue = 
> getSystemLinker().downcallHandle(
> addrCreateCommandQueue,
> MethodType.methodType(int.class, MemoryAddress.class, 
> MemoryAddress.class, MemoryAddress.class),
> FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER));
>
> var ppQueue = ID3D12CommandQueue.allocatePointer(scope);
>
> checkResult((int) 
> MH_ID3D12Device_CreateCommandQueue.invokeExact(pQueueDesc.address(),
> GUID(IID.IID_ID3D12CommandQueue).address(), ppQueue.address()));
>
> Full example here:
>
> https://github.com/brcolow/java-dx12/blob/master/src/main/java/com/dx12/DX12.java 
> <https://urldefense.com/v3/__https://github.com/brcolow/java-dx12/blob/master/src/main/java/com/dx12/DX12.java__;!!GqivPVa7Brio!NNn4WtIsLKjlTcTCh-TY2gYE6mbNNXrzVKMHA4rEupoedndflmeMdLXktTMoasJKTw999Fs$>
>
> Sorry if it's painfully obvious, this is the last question on this 
> topic I will ask!
>
> On Mon, Sep 14, 2020 at 11:45 AM Jorn Vernee <jorn.vernee at oracle.com 
> <mailto:jorn.vernee at oracle.com>> wrote:
>
>     Hi Michael,
>
>     Note that I passed -l dxgi to jextract when extracting dxgi.h,
>     that will making it so the dxgi library is used to link the
>     functions. d3d12 didn't seem to be needed. Doing that should avoid
>     the need to manually load the library like you've shown.
>
>     This is what I ended up with:
>
>     $jdk = ...
>     nal -Name jextract -Value "$jdk\bin\jextract.exe"
>     $I = "C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0"
>     jextract -d out -t org.jextract --filter "dxgi.h" -l dxgi --
>     "$I\shared\dxgi.h"
>     jextract -d out -t org.jextract --filter "guiddef.h" --
>     "$I\shared\guiddef.h"
>     jar -cf dxgi.jar -C out org
>
>     Jorn
>
>     On 14/09/2020 19:51, Michael Ennen wrote:
>>     It worked for me! Awesome!
>>
>>     One quick question:
>>
>>     I had to add the following:
>>
>>             LibraryLookup d3d12 = LibraryLookup.ofLibrary("D3D12");
>>             LibraryLookup dxgi = LibraryLookup.ofLibrary("dxgi");
>>
>>     To get the methods to be wired up, is that expected? I don't see
>>     it in your example.
>>
>>     Thanks again *so much*. This is a fantastic reference to get
>>     started as it handles some complexities like function
>>     pointers and the complexities of having a C API that really
>>     corresponds to a C++ API which seems to be the case
>>     with DirectX12.
>>
>>     On Mon, Sep 14, 2020 at 10:39 AM Michael Ennen
>>     <mike.ennen at gmail.com <mailto:mike.ennen at gmail.com>> wrote:
>>
>>         Ahhh, this makes so much more sense now.
>>
>>         Thank you both tremendously.
>>
>>         On Mon, Sep 14, 2020 at 6:39 AM Jorn Vernee
>>         <jorn.vernee at oracle.com <mailto:jorn.vernee at oracle.com>> wrote:
>>
>>             Ok, it looks like the formatting got messed up in the
>>             email, so I've
>>             uploaded the example here as well:
>>
>>             http://cr.openjdk.java.net/~jvernee/d3d12_example/Main.java
>>
>>             Jorn
>>
>>             On 14/09/2020 15:28, Jorn Vernee wrote:
>>             > I've tried it out on my machine as well (I'm also on
>>             Windows). Here is
>>             > a little bit more complete example that prints out the
>>             adapter
>>             > description
>>             >
>>             > If you have extracted the shared/dxgi.h and the
>>             shared/guiddef.h
>>             > headers as well, you can do something like this:
>>             >
>>             >
>>             > import jdk.incubator.foreign.FunctionDescriptor;
>>             > import jdk.incubator.foreign.MemoryAccess;
>>             > import jdk.incubator.foreign.MemoryAddress;
>>             > import jdk.incubator.foreign.MemoryLayout;
>>             > import jdk.incubator.foreign.MemorySegment;
>>             > import jdk.incubator.foreign.NativeScope;
>>             > import org.jextract.dxgi_h;
>>             > import org.jextract.guiddef_h;
>>             >
>>             > import java.lang.invoke.MethodHandle;
>>             > import java.lang.invoke.MethodType;
>>             > import java.nio.charset.StandardCharsets;
>>             >
>>             > import static jdk.incubator.foreign.CSupport.*;
>>             > import static org.jextract.dxgi_h.*;
>>             >
>>             > public class Main {
>>             >
>>             >     public static void main(String[] args)throws
>>             Throwable {
>>             >         try (NativeScope scope
>>             =NativeScope.unboundedScope()) {
>>             >             // IDXGIFactory1** dxgiFactory;
>>             > var ppDxgiFactory =IDXGIFactory1.allocatePointer(scope);
>>             >             // HRESULT =
>>             CreateDXGIFactory1(_uuid(dxgiFactory),
>>             > &dxgiFactory))
>>             >
>>             checkResult(dxgi_h.CreateDXGIFactory1(IID_IDXGIFactory1,ppDxgiFactory));
>>             >             // IDXGIFactory1* MemorySegment pDxgiFactory
>>             >
>>             =asSegment(MemoryAccess.getAddress(ppDxgiFactory),IDXGIFactory1.$LAYOUT());
>>             >
>>             >             // (This)->lpVtbl MemorySegment vtbl
>>             >
>>             =asSegment(IDXGIFactory1.lpVtbl$get(pDxgiFactory),IDXGIFactory1Vtbl.$LAYOUT());
>>             >             // lpVtbl->EnumAdapters1 MemoryAddress
>>             addrEnumAdapters
>>             > =IDXGIFactory1Vtbl.EnumAdapters1$get(vtbl);
>>             >
>>             >             // link the pointer MethodHandle
>>             MH_EnumAdapters1
>>             > =getSystemLinker().downcallHandle(
>>             >                 addrEnumAdapters,
>>             >
>>             MethodType.methodType(int.class,MemoryAddress.class,int.class,MemoryAddress.class),
>>             > FunctionDescriptor.of(C_INT,C_POINTER,C_INT,C_POINTER));
>>             >
>>             >             /* [annotation][out] _COM_Outptr_
>>             IDXGIAdapter1** */
>>             > MemorySegment ppOut =IDXGIAdapter1.allocatePointer(scope);
>>             >
>>             checkResult((int)MH_EnumAdapters1.invokeExact(pDxgiFactory.address(),0,ppOut.address()));//
>>
>>             > IDXGIAdapter1* MemorySegment pAdapter
>>             >
>>             =asSegment(MemoryAccess.getAddress(ppOut),IDXGIAdapter1.$LAYOUT());
>>             >
>>             >             // (This)->lpVtbl MemorySegment vtbl2
>>             >
>>             =asSegment(IDXGIAdapter1.lpVtbl$get(pAdapter),IDXGIAdapter1Vtbl.$LAYOUT());
>>             >             // lpVtbl->EnumAdapters1 //
>>             > HRESULT(*)(IDXGIAdapter1*,DXGI_ADAPTER_DESC1*)
>>             MemoryAddress
>>             > addrGetDesc1 =IDXGIAdapter1Vtbl.GetDesc1$get(vtbl2);
>>             >
>>             >             // link the pointer MethodHandle MH_GetDesc1
>>             > =getSystemLinker().downcallHandle(
>>             >                 addrGetDesc1,
>>             >
>>             MethodType.methodType(int.class,MemoryAddress.class,MemoryAddress.class),
>>             > FunctionDescriptor.of(C_INT,C_POINTER,C_POINTER));
>>             >
>>             >             /* DXGI_ADAPTER_DESC1* */ MemorySegment pDesc
>>             > =DXGI_ADAPTER_DESC1.allocate(scope);
>>             >
>>             checkResult((int)MH_GetDesc1.invokeExact(pAdapter.address(),pDesc.address()));
>>             >
>>             >             // print description MemorySegment descStr
>>             > =DXGI_ADAPTER_DESC1.Description$slice(pDesc);
>>             >             String str =new
>>             > String(descStr.toByteArray(),StandardCharsets.UTF_16LE);
>>             >             System.out.println(str);
>>             >         }
>>             >     }
>>             >
>>             >     public static MemorySegment asSegment(MemoryAddress
>>             > addr,MemoryLayout layout) {
>>             >         return MemorySegment.ofNativeRestricted(addr,
>>             > layout.byteSize(),Thread.currentThread(),null,null);
>>             >     }
>>             >
>>             >     static final MemorySegment IID_IDXGIFactory1 =GUID(
>>             >             (int)0x770aae78,
>>             >             (short)0xf26f,
>>             >             (short)0x4dba,
>>             >             new byte[]{(byte)0xa8,0x29,0x25,0x3c,
>>             (byte)0x83,
>>             > (byte)0xd1, (byte)0xb3, (byte)0x87});
>>             >
>>             >     static final MemorySegment GUID(int Data1,short
>>             Data2,short
>>             > Data3,byte[] Data4) {
>>             >         MemorySegment ms
>>             > =MemorySegment.allocateNative(guiddef_h.GUID.$LAYOUT());
>>             >         guiddef_h.GUID.Data1$set(ms, Data1);
>>             >         guiddef_h.GUID.Data2$set(ms, Data2);
>>             >         guiddef_h.GUID.Data3$set(ms, Data3);
>>             >
>>             guiddef_h.GUID.Data4$slice(ms).copyFrom(MemorySegment.ofArray(Data4));
>>             >         return ms;
>>             >     }
>>             >
>>             >     private static final int S_OK =0x00000000;
>>             >
>>             >     private static void checkResult(int result) {
>>             >         switch (result) {
>>             >             case S_OK -> {}
>>             >             default ->throw new
>>             IllegalStateException("Unknown result:
>>             > " +String.format("%X8", result));
>>             >         }
>>             >     }
>>             > }
>>             >
>>             >
>>             > Which on my machine prints: NVIDIA GeForce GTX 1050 Ti
>>             >
>>             > HTH,
>>             > Jorn
>>             >
>>             > On 14/09/2020 12:52, Maurizio Cimadamore wrote:
>>             >> I think there's something off in here:
>>             >>
>>             >>> MemorySegment segment =
>>             >>>
>>             MemorySegment.allocateNative(dxgi_h.IDXGIFactory1Vtbl.$LAYOUT().byteSize());
>>
>>             >>>
>>             >>> MemoryAddress address = segment.address().addOffset(64);
>>             >> I see a couple of issues:
>>             >>
>>             >> 1) how do you determine that the offset of the
>>             function address you
>>             >> want to obtain is 64 byte from the start? Didn't
>>             jextract give you a
>>             >> getter for that?
>>             >>
>>             >> 2) Even assuming 64 byte is the correct offset, note
>>             that the segment
>>             >> will be initialized to all zeros - I presume this
>>             vtable must be
>>             >> filled in somehow, or perhaps obtained from a global
>>             variable?
>>             >>
>>             >> From your earlier email I see this:
>>             >>
>>             >>> interface IDXGIFactory
>>             >>>       {
>>             >>>           CONST_VTBL struct IDXGIFactoryVtbl *lpVtbl;
>>             >>>       };
>>             >> So... perhaps once yo create a IDXGIFactory, you can
>>             just grab the
>>             >> pointer to the vtable by accessing its `lpVtbl` field
>>             - no need to
>>             >> allocate a new segment (the library has done the
>>             allocation for you).
>>             >>
>>             >> If I'm correct, this can be achieved with something
>>             like (not sure if
>>             >> the names are going to be 100% correct since I don't
>>             have a
>>             >> jextracted version of the API with me - so beware, I
>>             have NOT tested
>>             >> this :-) ):
>>             >>
>>             >> var dxgiFactoryPtr =
>>             >>
>>             MemoryAccess.getAddress(MemorySegment.ofNativeRestricted(),
>>             >> dxgiFactory);
>>             >> var lpVtbl =
>>             >>
>>             MemoryAccess.getAddress(MemorySegment.ofNativeRestricted(),
>>             >> dxgiFactoryPtr);
>>             >> var vtable = RuntimeHelper.ofArrayRestricted(lpVtbl,
>>             >> IDXGIFactory1Vtbl.$LAYOUT(), 1); //1
>>             >> var address = IDXGIFactory1Vtbl$EnumAdapters$get(vtable);
>>             >>
>>             >>
>>             >> And this should give the address pointer you are
>>             looking for. We need
>>             >> to smooth the edges especially around (1) - e.g. to
>>             turn a random
>>             >> native pointer into a struct with given layout
>>             (jextract should
>>             >> generate a static helper for that, see [1]) - but with
>>             the code above
>>             >> you should be able to get there, I hope.
>>             >>
>>             >> P.S.
>>             >> In these situations, my suggestion is, especially when
>>             attacking a
>>             >> native library for the first time, to always try the
>>             library directly
>>             >> using C and see what happens, to understand exactly
>>             what kind of
>>             >> pattern/idiom the library requires. I did that many
>>             times and
>>             >> realized my assumptions on how library worked were
>>             wrong; other users
>>             >> have posted similar instances in this mailing list.
>>             Once you get
>>             >> things working in C, porting the code in Java using
>>             the Panama API is
>>             >> typically a trivial matter.
>>             >>
>>             >> Maurizio
>>             >>
>>             >> [1] - https://bugs.openjdk.java.net/browse/JDK-8253102
>>             >>
>>             >>
>>             >> On 13/09/2020 02:37, Michael Ennen wrote:
>>             >>> 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 <mailto: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 <mailto: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 <mailto: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
>>
>>
>>
>>     -- 
>>     Michael Ennen
>
>
>
> -- 
> Michael Ennen


More information about the panama-dev mailing list