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