-
-
Notifications
You must be signed in to change notification settings - Fork 652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How does ThreadLocalUtil#setCapabilities works? #875
Comments
Whoooops, I didn't realised that all the code comments are on the top of the class... I'm sorry!
So yeah, it works as I expected it to do. Now I just have a follow up question, do you know, whether there is somewhere any documentation to the "reserved3" field in the struct? I couldn't find any. |
Hey @Berstanio, There's no documentation, it's just some reserved space before the function pointers. It was never used for anything and However, there's no denying that it's a nasty hack and I plan to get rid of it in LWJGL 4. The problem with OpenGL, OpenGL ES and OpenAL Soft (with |
Hey @Spasi , Also, as I understand it, the thread dependent lookup is only needed, if we render on multiple different threads, right? So if I don't get proper "reserved3" support into substratevm native-image, could I just fork of the natives, make the capabilities function pointer array global and use that, if I impose the limitation, that multi thread rendering is not allowed? Or do I misunderstand something? |
Hey @Berstanio, Your understanding is correct, it would have to use In OpenGL's case, having different contexts is not so uncommon. You can have a single GPU/driver but contexts with different capabilities (core vs compatibility, forward compatibility enabled or not). You can have multiple GPUs from different vendors or different generations from the same vendor. Multithreading is not even a requirement for a conflict to arise, you can have a single rendering thread binding multiple OpenGL contexts. Anyway, I'm not sure why Native Image would have trouble with the As for a workaround, if you're going down the fork route: Just drop the natives (i.e. |
Hey @Spasi ,
I'm not quite sure yet too, my first guess would be, that the struct is static in the executable data section or something like that. But this is just a guess. Until the issue is properly sorted out on the graal end, your workaround will be very helpful to further test around with native image and lwjgl3, thank you a lot for pointing me out to this! |
Hey @Spasi , I was able to create substitutions for the OpenGL classes, and now native-images runs fine on linux and mac without a fork, thanks a lot again 🥳 However, windows is still a problem, since it also uses reserved2. oracle/graal#6428 (comment) Also, it seems lucky that linux/mac currently works, since it seems there are also code pathes that want to access the EnvData in reserved2. |
Hey @Berstanio, That one won't be as easy to fix and indeed, it affects Linux/macOS ( You'll have to revert Btw, got any insight to what may be going wrong with Native Image? Is it using the |
Hey @Spasi ,
That was what I was afraid of. I don't really want to build my own natives for every platform etc. Buut, I have some rather good news:
Yes, after some digging I think I have now some understanding about it!
This is the result on a "default" execution of native-image. By default native-image has Isolates activated, which seems to mmap the static heap per isolate. That seems to be, what we see here.
So, the JNINativeInterface_ struct lies in a section of the binary, that was made read only on purpose by native-image. The easiest way I found to work around this is to disable Isolates and disable the "Read-Only" property of the __DATA section, by passing: One last thing I figured I might should mention, it may be that Espresso Truffle (a graal Java interpreter) uses the reserved0-2 fields internally, just so that you are aware. But I guess, no one runs java games through a interpreter, so shouldn't be any problem. |
Hey @Berstanio, Thanks for the interesting information! Some feedback that might help:
I cloned Graal and examined the code a bit, but couldn't find a better explanation. I'm not at all familiar with that codebase, so you might have more luck than me. What I did find though is why |
Oh no, I forgot about:
@Berstanio could you please confirm that this is where it crashes on Native Image (with Isolates enabled)? It would be good news if that is indeed the case. We don't have to use |
Hey @Spasi , First of all, thanks for all the clarifications and insights! Windows there seems to be more "reasonable" working. If I patch out the "ThreadLocalUtil#setFunctionMissingAddresses" function and run ThreadLocalUtil#setupEnvData on startup manually (cause the reserved2 == null check is broken), it runs fine there. This is believable imo.
This is a nice finding that I totally missed! The workaround is probably not ideal, but it should work! Also on another note, should I pr my lwjgl3 reflection/jni/substituions rules for native-image? I was not sure, whether lwjgl3 will even get a next release or whether the next release will be lwjgl4? |
Hi @Spasi , just a little follow up question about this:
It would be great to have this inside lwjgl3, so I was wondering whether I should try and build a pr, or whether you want to take care of this? |
Hey @Berstanio, I've had GraalVM downloaded and waiting on my mac for the past month... I meant to do some testing on my own before pushing fixes, but other stuff kept me super busy, then I completely forgot about it! I'll make sure the next 3.3.3 snapshot has the |
Hey @Spasi ,
Thank you very much, that sounds great!
Dealing with that should be easy, I would solve it like this: I plan to pr all my lwjgl3 native-image configuration, if I have the feeling they are good enough. Please note, that the "master" branch contains my old seemingly unneccessary substitutions, the "what" branch (named after the confusion I had, when stuff was just working out of nowhere), is the up-to date one. |
Hey @Berstanio, I just pushed the
Please let me know how it works for you. |
Hey @Spasi , thank you very much for your work, I will try it out!
As I understand it, you don't like the idea of having Also, I think this is not neccessary, since it is only called by JNI? lwjgl3/config/native-image/META-INF/native-image/reflect-config.json Lines 12 to 23 in ef498be
|
Yeah, I mean, if we can just put these json files under
Not sure I understand this, could you post some example code?
I think it's necessary because we use reflection here:
and pass the method to JNI to set it up (with |
Sure, I have done this in my code: access.registerSubtypeReachabilityHandler((duringAnalysisAccess, aClass) ->
// Would only need to be one constructor I think, but w/e
RuntimeReflection.register(aClass.getDeclaredConstructors()),
org.lwjgl.system.Struct.class);
access.registerSubtypeReachabilityHandler((duringAnalysisAccess, aClass) ->
// Would only need to be one constructor I think, but w/e
RuntimeReflection.register(aClass.getDeclaredConstructors()),
org.lwjgl.system.StructBuffer.class); This way, all structs are able to get allocated by unsafe, but only if they are reachable. This kind of conditional registration can't be currently done using the jsons, sadly.
Ahh, I see! Since it is a direct and clear reflection access, native-image is probably able to register that automatically based on analysis, so I never had a problem with not defining it. |
Right, this does indeed apply the handler to all subclasses. However, we won't be needing it, I've now performance tested the refactored structs and there hasn't been a negative impact.
You're correct, works fine without it. I've updated the branch with various cleanups. |
Ahh, thats great to hear!
Thank you very much, I tested them on mac and it works fine! Once the fixes are integrated into a snapshot, I can also do more complex tests on other platforms. |
@Berstanio thank you for your patience and great feedback! The above have been integrated and will be available in the next 3.3.3 snapshot. |
Thank you very much for implementing this, I highly appreciate it! |
Disclaimer: I work on the GraalVM team. Good to see that lwjgl3 is now compatible with GraalVM Native Image! If this is tested somewhere (e.g., using GitHub Actions), maybe the library could be added to the list at https://www.graalvm.org/native-image/libraries-and-frameworks/? Feel free to get in touch if you have any questions! |
Hey @fniephaus, There is now a GitHub Actions workflow that builds and tests LWJGL, then runs a simple demo with OpenJDK JIT, GraalVM JIT and GraalVM Native Image: Afaik GraalVM cannot cross-compile, so only the Linux x64, macOS x64 and Windows x64 jobs build and run the demo. |
Cool, thanks for the info, @Spasi. I think the library may qualify to listed as "fully tested" at https://www.graalvm.org/native-image/libraries-and-frameworks/. Click here for instructions what you'd need to do. :) |
Question
Hey,
first of all I hope this is the right place to ask such question.
I'm currently experementing with lwjgl3 and native-image. Currently I get a segault in ThreadLocalUtil#setCapabilities and I would like to understand the method first, before I proceed with e.g. opening a graal issue.
So, how I understand it
capabilities
a array of function pointer. This array will be later used to dispatch different GL functions.Then, in the line
memPutAddress(env_p + CAPABILITIES_OFFSET, capabilities);
, the function array will be put insidereserved3
field in the JNIEnv struct.From there it will be used to dispatch the functions.
Is that correct?
The text was updated successfully, but these errors were encountered: