LWJGL / lwjgl3

LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications.
https://www.lwjgl.org
BSD 3-Clause "New" or "Revised" License
4.67k stars 628 forks source link

Port from JNI to Java foreign #853

Closed Snowiiii closed 1 year ago

Snowiiii commented 1 year ago

Description

foreign or Project Panama is Build in in Java and should be Prefered over JNI due to Better Performance & Its Features

ws909 commented 1 year ago

That’s part of the switch to LWJGL 4. It’s one of the primary changes from version 3 to 4.

Snowiiii commented 1 year ago

would recommend to make a New Milestone for LWJGL 4 and add this

tlf30 commented 1 year ago

I cannot speak for spasi, but I imagine that LWJGL 4 would get its own repo and not be a part of this one. It would probably make more sense just to wait until it is created before attempting to organize a milestone for it.

Again, I cannot speak for spasi, but it will probably be a bit since the foreign API is still changing. Even in the up coming jdk 20 there are major changes to the memory API, and from 18 to 19 there were other major changes. It would not make sense to get started before the API stabilizes first. Perhaps with jdk 21 there won't be many additional changes to the API, but it is too soon to tell yet. Personally I hope they take as long as they need to to get the API right, because we are going to be stuck with it for a long time if there are major issues.

Spasi commented 1 year ago

Hey all,

The current plan is this:

Obviously, LWJGL 4 will be based on Panama Foreign and will require a cutting edge Java version. There will be a long alpha/beta period. Btw, the JDK 20 Foreign API is obsolete as well, it's already changed for 21 (and looking great!).

Snowiiii commented 1 year ago

Sounds great, I love you @Spasi :kissing:, If there is any way i can help let me Know i have good Java knowledge

Glavo commented 1 year ago

Hey all,

The current plan is this:

  • Add hwloc bindings.
  • Release 3.3.2.
  • LWJGL 3 goes into "feature freeze" mode, meaning no additional bindings will be added and no more sophisticated work will be done in the core module.
  • LWJGL 3 will continue to be maintained for as long as it makes sense. This includes the usual updates to the existing bindings. I expect this situation to last for several years.
  • LWJGL 4 will be a separate repo with a clean commit history. There might be some refactoring in the future that enables reuse of binding templates between the two repos, for easier maintainance. However, not all LWJGL 3 bindings will make it to LWJGL 4, it's an opportunity for cleanup.

Obviously, LWJGL 4 will be based on Panama Foreign and will require a cutting edge Java version. There will be a long alpha/beta period. Btw, the JDK 20 Foreign API is obsolete as well, it's already changed for 21 (and looking great!).

That sounds great.

I hope LWJGL 4 can start development as soon as possible because some designs of Panama are unexpectedly immature.

I used Panama in some simple use cases, only to find some obvious functional deficiencies (such as not supporting set the calling conventions). I think Panama needs to get feedback through real world use cases, and LWJGL 4 is an excellent test ground.

Now Panama is still in preview status, and its API has no guarantee, so the maintainers of Panama can make breaking changes to the API based on feedback. Starting to develop LWJGL 4 earlier can find problems earlier and feed back problems earlier. If develop LWJGL 4 later, we may miss the release cycle of the new version of Java, or even miss the preview stage, resulting in the problem being frozen to the official version.

ws909 commented 1 year ago

(such as not supporting set the calling conventions)

That was an issue I ran into too. I tried to call into Cocoa from Java, which crashed. After a while of debugging, I realized they hadn't even implemented the correct calling conventions for MacOS on Aarch64 at all.

Spasi commented 1 year ago

such as not supporting set the calling conventions

Isn't this only necessary on Windows x86, for stdcall functions? Is there another use-case?

I realized they hadn't even implemented the correct calling conventions for MacOS on Aarch64 at all

Have you tried a newer build? Afaict there is now aarch64 support for Linux/macOS/Windows.

ws909 commented 1 year ago

Have you tried a newer build? Afaict there is now aarch64 support for Linux/macOS/Windows.

It's been a few months ago, now. I figured I'd just try again later, hoping they'd have implemented it by then. If they have, thanks for letting me know. :)

Glavo commented 1 year ago

Have you tried a newer build? Afaict there is now aarch64 support for Linux/macOS/Windows.

It's been a few months ago, now. I figured I'd just try again later, hoping they'd have implemented it by then. If they have, thanks for letting me know. :)

I'm sure Java 19 does support the macOS aarch64 platform.

image

image

ws909 commented 1 year ago

@Glavo Oh, it's been a while, but I still have some test code around:

JDK 19:

final var objCLibrary = org.lwjgl.system.macosx.ObjCRuntime.getLibrary();
final var cgLibrary = MacOSXLibrary.getWithIdentifier("com.apple.CoreGraphics");

final var objc_msgSend = objCLibrary.getFunctionAddress("objc_msgSend");
final var addressCGImageCreate = cgLibrary.getFunctionAddress("CGImageCreate");

var layout_objc_msgSend = java.lang.foreign.FunctionDescriptor.of(
        ValueLayout.JAVA_LONG,
        ValueLayout.JAVA_LONG,
        ValueLayout.JAVA_LONG
);

var layoutCGImageCreate = java.lang.foreign.FunctionDescriptor.of(
        ValueLayout.JAVA_LONG, // CGImageRef (*CGImage)

        ValueLayout.JAVA_LONG.withName("width"), // size_t
        ValueLayout.JAVA_LONG.withName("height"), // size_t
        ValueLayout.JAVA_LONG.withName("bitsPerComponent"), // size_t
        ValueLayout.JAVA_LONG.withName("bitsPerPixel"), // size_t
        ValueLayout.JAVA_LONG.withName("bytesPerRow"), // size_t
        ValueLayout.JAVA_LONG.withName("space"), // CGColorSpaceRef (*CGColorSpace)
        ValueLayout.JAVA_INT.withName("bitmapInfo"), // CGBitmapInfo (uint32_t)
        ValueLayout.JAVA_LONG.withName("provider"), // CGDataProviderRef (*CGDataProvider)
        ValueLayout.JAVA_LONG.withName("decode"), // *CGFloat
        ValueLayout.JAVA_BOOLEAN.withName("shouldInterpolate"), // bool
        ValueLayout.JAVA_INT.withName("intent") // CGColorRenderingIntent (int32_t)
);

final var linker = Linker.nativeLinker();
final var handle_objc_msgSend = linker.downcallHandle(MemoryAddress.ofLong(objc_msgSend), layout_objc_msgSend);
final var handleCGImageCreate = linker.downcallHandle(MemoryAddress.ofLong(addressCGImageCreate), layoutCGImageCreate); // Crash here. The previous call executed fine, though.

Stack trace:

Caused by: java.lang.UnsupportedOperationException: Call type not supported on this platform
    at java.base/jdk.internal.foreign.abi.aarch64.CallArranger$StorageCalculator.stackAlloc(CallArranger.java:206)
    at java.base/jdk.internal.foreign.abi.aarch64.CallArranger$StorageCalculator.stackAlloc(CallArranger.java:217)
    at java.base/jdk.internal.foreign.abi.aarch64.CallArranger$StorageCalculator.nextStorage(CallArranger.java:244)
    at java.base/jdk.internal.foreign.abi.aarch64.CallArranger$UnboxBindingCalculator.getBindings(CallArranger.java:395)
    at java.base/jdk.internal.foreign.abi.aarch64.CallArranger.getBindings(CallArranger.java:146)
    at java.base/jdk.internal.foreign.abi.aarch64.CallArranger.arrangeDowncall(CallArranger.java:153)
    at java.base/jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker.arrangeDowncall(MacOsAArch64Linker.java:56)
    at java.base/jdk.internal.foreign.abi.AbstractLinker.lambda$downcallHandle$0(AbstractLinker.java:52)
    at java.base/jdk.internal.foreign.abi.SoftReferenceCache$Node.get(SoftReferenceCache.java:52)
    at java.base/jdk.internal.foreign.abi.SoftReferenceCache.get(SoftReferenceCache.java:38)
    at java.base/jdk.internal.foreign.abi.AbstractLinker.downcallHandle(AbstractLinker.java:50)
    at java.base/java.lang.foreign.Linker.downcallHandle(Linker.java:221)
// Caused by: linker.downcallHandle(MemoryAddress.ofLong(addressCGImageCreate), layoutCGImageCreate);

So eventually, I just decided to do this in C (set MacOS Dock icon), and create a PR in the GLFW repository instead.

Oh, actually, looking back at it, the issue might not've been there. You see, I also put this into that function:

final var cgLibrary = MacOSXLibrary.getWithIdentifier("com.apple.CoreGraphics");
//final var cgLibrary = MacOSXLibrary.getWithIdentifier("CoreGraphics.framework");
//final var cgLibrary = MacOSXLibrary.getWithIdentifier("CoreGraphics.framework");
//final var cgLibrary = MacOSXLibrary.getWithIdentifier("CoreGraphics");
//final var cgLibrary = MacOSXLibrary.getWithIdentifier("/System/Library/Frameworks/CoreGraphics.framework");
//final var cgLibrary = MacOSXLibrary.create("com.apple.CoreGraphics");
//final var cgLibrary = MacOSXLibrary.create("CoreGraphics.framework");
//final var cgLibrary = MacOSXLibrary.create("CoreGraphics");
//final var cgLibrary = MacOSXLibrary.create("/System/Library/Frameworks/CoreGraphics.framework");
System.out.println("Library: {");
System.out.println("    " + cgLibrary.address());
System.out.println("    " + cgLibrary.getPath());
System.out.println("    " + cgLibrary.getName());
System.out.println("}");

... which prints:

Library: {
    5134102000
    null
    com.apple.CoreGraphics
}

So the problem might've actually been with locating the library.

Comments in stackAlloc (JDK 19):

Implementation limit: each arg must take up at least an 8 byte stack slot (on the Java side) There is currently no way to address stack offsets that are not multiples of 8 bytes The VM can only address multiple-of-4-bytes offsets, which is also not good enough for some ABIs see JDK-8283462 and related issues

macos-aarch64 ABI potentially requires addressing stack offsets that are not multiples of 8 bytes Reject such call types here, to prevent undefined behavior down the line Reject if the above stack-slot-aligned offset does not match the offset the ABI really wants Except for variadic arguments, which are passed at 8-byte-aligned offsets

ws909 commented 1 year ago

The JEP for JDK 19, JEP 424:

the CLinker implementation implements several calling conventions out-of-the-box: Linux/x64, Linux/AArch64, macOS/x64, and Windows/x64

No mention of MacOS/AArch64.

Latest JEP on FFI, JEP 434:

the native linker implementation supports several calling conventions out-of-the-box: Linux/x64, Linux/AArch64, macOS/x64, macOS/AArch64 and Windows/x64.

MacOS/AArch64 is now mentioned. This is the JEP for the FFI support in JDK 20, set to release in 10 days. Going by the norm, it'll be delayed, but this still means it's available soon in general availability releases (in preview).