Windows DXGI Experiment

Hugo De Vaan hdevaan76 at gmail.com
Thu Feb 27 16:32:05 UTC 2025


As Jorn pointed out to me, I missed another indirection in my previous
post. I guess it shows that I originally came from a pure C environment
before my Java days and so have little to no experience in C++
specifically. It's not as if in C we never had pointers to pointers, but I
feel C++ really takes it to another level. This is probably going to trip
me up a few more times, but that's okay, I am now at least aware of it and
it will be the first thing I check when my code runs into "FMM over C++"
bugs.

Anyway, the following snippet is taken from a fully working class and uses
the post incubation FFM API (replacing things like NativeScope,
MemoryAddress, MemoryAccess, and so forth from the 2020 example). I thought
I'd post it here to help other people who might Google their way into
examples or tutorials from the incubation era (an unavoidable risk for any
JDK preview projects, I guess).

private static MemorySegment DEFINE_GUID(
    Arena arena,
    int data1, int data2, int data3,
    int data4_0, int data4_1, int data4_2, int data4_3,
    int data4_4, int data4_5, int data4_6, int data4_7) {

    MemorySegment refIID = IID.allocate(arena);
    IID.Data1(refIID, data1);
    IID.Data2(refIID, (short)data2);
    IID.Data3(refIID, (short)data3);

    MemorySegment data4 = IID.Data4(refIID);
    IID.Data4(data4, 0, (byte) data4_0);
    IID.Data4(data4, 1, (byte) data4_1);
    IID.Data4(data4, 2, (byte) data4_2);
    IID.Data4(data4, 3, (byte) data4_3);
    IID.Data4(data4, 4, (byte) data4_4);
    IID.Data4(data4, 5, (byte) data4_5);
    IID.Data4(data4, 6, (byte) data4_6);
    IID.Data4(data4, 7, (byte) data4_7);

    return refIID;
}

static final MemorySegment IID_IDXGIFactory1 =
    DEFINE_GUID(
        Arena.global(),
        0x770aae78, 0xf26f, 0x4dba,
        0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87);

public static final void main(String[] args) {
    Linker linker = Linker.nativeLinker();

    SymbolLookup symbols = SymbolLookup.
        libraryLookup(
        "C:\\Windows\\System32\\dxgi.dll",
        arena);

    try (Arena arena = Arena.ofConfined()) {
        MemorySegment factoryPointer =
            arena.allocate(ValueLayout.ADDRESS);

        int hresult = dxgi_h.CreateDXGIFactory1(
            IID_IDXGIFactory1, factoryPointer);

        System.out.println(
            "CreateDXGIFactory: " +
            HexFormat.of().toHexDigits(hresult));

        MemorySegment factory =
            IDXGIFactory1.reinterpret(
                factoryPointer.get(dxgi_h.C_POINTER, 0L),
                arena,
                null);

        MemorySegment factoryVtable =
            IDXGIFactory1.lpVtbl(factory);

        MemorySegment EnumAdapters1 =
            IDXGIFactory1Vtbl.EnumAdapters1(factoryVtable);

        MemorySegment adapterPointer =
            arena.allocate(dxgi_h.C_POINTER);

        hresult = IDXGIFacotry1Vtbl.EnumAdapters1.invoke(
            EnumAdapters1, factory, 0, adapterPointer);

        System.out.println(
            "EnumAdapters: " +
            HexFormat.of().toHexDigits(hresult));

        MemorySegment adapter =
            IDXGIAdapter1.reinterpret(
                adapterPointer.get(dxgi_h.C_POINTER, 0L),
                arena,
                null);

        MemorySegment adapterVtable =
            IDXGIAdapter1.lpVtbl(adapter);

        MemorySegment GetDescriptor1 =
            IDXGIAdapter1Vtbl.GetDesc1(adapterVtable);

        MemorySegment descriptorPointer =
            DXGI_ADAPTER_DESC.allocate(arena);

        hresult = IDXGIAdapter1Vtbl.GetDesc1.invoke(
            GetDescriptor1, adapter, descriptorPointer);

        System.out.println(
            "GetDescriptor: " +
            HexFormat.of().toHexDigits(hresult));

        MemorySegment cstring = DXGI_ADAPTER_DESC1.
            Description(descriptorPointer);

        String jstring = cstring.getString(
            0, StandardCharsets.UTF_16LE);

        System.out.println("Adapter[0]: " + jstring);
    } catch (Throwable t) {
        t.printStackTrace();
    }
}

This should print the descriptor of the first adapter (for example: "NVIDIA
GeForce RTX 4060"). Anyone trying this in a headless environment such as a
cloud node might want to be careful, because I haven't tested whether or
not a software adapter would also qualify for this function (if it doesn't,
I expect this snippet will crash your JVM).

Thanks again for the help, getting over the first hurdles makes all the
difference between being able to continue a project at all or staying
completely stuck. I still got (and will get) some things wrong, but with
the basic parts up and running, I will be able to figure out problems for
myself.

Kind regards,
Hugo
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20250227/9c9dabd3/attachment.htm>


More information about the panama-dev mailing list