Fetch graphics card info and make it available to script
It should be possible, for example, to at least fetch the graphic card manufacturer (intel/nvdia/amd) in order, for example, to set VK_ICD_FILENAME correctly for Vulkan application.
Fetching OpenGL core context version and Vulkan version could also be interesting, simply to test if drivers are installed (in 32 bits and 64 bits).
This is somewhat related to #1854.
#1854 is more general, but yes. I see three ways of doing it:
- Use LWJGL to get the rendering infos (advantage: pure java)
- Use glxinfo and vulkaninfo (and call the program from Java) (advantage: nearly nothing to do)
- Compile a simple C++ test program to check this (only advantage: can be compiled in 32 bits and 64 bits to check if the user have installed OpenGL/Vulkan 32 bits drivers)
I can do the GL or Vulkan calls quite easily ^^.
I have normally a working LWJGL code, which compiles and execute in js, but I do not know how to check the returned value. Current code (most part are simply copy paste from LWJGL tutorial ^^):
package org.phoenicis.tools.system;
import org.phoenicis.configuration.security.Safe;
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.vulkan.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.glfw.GLFWVulkan.*;
@Safe
class GraphicsProperties {
public GraphicsProperties() {
Vendor = "Unknown";
OpenGLVersion = "Unsupported";
VulkanVersion = "Unsupported";
}
public String toString() {
return Vendor + " " + OpenGLVersion + " " + VulkanVersion;
}
public String getVendor() {
return this.Vendor;
}
public String getOpenGLVersion() {
return this.OpenGLVersion;
}
public String getVulkan() {
return this.VulkanVersion;
}
public String Vendor;
public String OpenGLVersion;
public String VulkanVersion;
}
@Safe
// Code from LWJGL tutorial
public class GraphicsPropertiesFetcher {
private long window;
private void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if (!glfwInit())
throw new IllegalStateException("Unable to initialize GLFW");
// Configure GLFW
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); does not work if opengl <3.2
// Create the window
window = glfwCreateWindow(300, 300, "Test Window", NULL, NULL);
if (window == NULL)
throw new RuntimeException("Failed to create the GLFW window for testing graphic card capabilities");
}
private void terminate() {
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private void FetchVendorOpenGLVersion(GraphicsProperties graphicsProperties) {
// Make the OpenGL context current
glfwMakeContextCurrent(window);
GL.createCapabilities();
graphicsProperties.Vendor = glGetString(GL_VENDOR);
graphicsProperties.OpenGLVersion = glGetString(GL_VERSION);
graphicsProperties.OpenGLVersion = graphicsProperties.OpenGLVersion.substring(0, graphicsProperties.OpenGLVersion.indexOf(' '));
GL.destroy();
}
private void FetchVulkanVersion(GraphicsProperties graphicsProperties) {
if (!glfwVulkanSupported()) {
return;
}
int version = VK.getInstanceVersionSupported();
graphicsProperties.VulkanVersion = String.valueOf(version >> 22) + "." + String.valueOf((version >> 12) & 0x3ff) + "." + String.valueOf(version & 0xfff);
}
public GraphicsProperties GetProperties() {
GraphicsProperties graphicsProperties = new GraphicsProperties();
init();
FetchVendorOpenGLVersion(graphicsProperties);
FetchVulkanVersion(graphicsProperties);
terminate();
System.out.println(graphicsProperties.Vendor);
System.out.println(graphicsProperties.OpenGLVersion);
System.out.println(graphicsProperties.VulkanVersion);
return graphicsProperties;
}
}
but I do not know how to check the returned value.
What do you mean?
To make GraphicsPropertiesFetcher accessible from the scripts you only need to add a
@Bean
public GraphicsPropertiesFetcher graphicsPropertiesFetcher() {
return new GraphicsPropertiesFetcher();
}
method to ToolsConfiguration.
Afterwards you can access the GraphicsPropertiesFetcher in your scripts via:
const graphicsProperties = Bean("graphicsPropertiesFetcher").GetProperties();
And how do I access the content of the structure/class returned ? I tried graphicsProperties.Vendor, but it returned undefined.
That is exactly how you should do it. If you are unsure if the Java class works as you expect you can also add some debugging code in it, e.g. some System.out.println(....); statements. The most likely scenario is that glGetString(GL_VENDOR) returns null which may be interpreted as undefined by JS.
I have the error "no bean 'graphicsPropertiesFetcher' available" :thinking:.
Did you add the above mentioned method to ToolsConfiguration and recompile Phoenicis afterwards?
Yes, I did. Maybe I have done a spelling error somewhere because it worked some hours ago.
Okay, so the Vendor and GL Version are :
VMware, Inc.
3.1 Mesa 18.2.8
However, in .js I have undefined for the vendor (did not test GL version)
I will also have to do some work on the version to have it in the format 310 (which I will do in js when it works).
You can try adding a toString method to GraphicsProperties to check whether the object contains the right information. The method would then look like this:
public String toString() {
return Vendor + " " + OpenGLVersion + " " + VulkanVersion;
}
Afterwards you can test the output via:
Java
System.out.println(graphicsProperties.toString());
JavaScript
print(Bean("graphicsPropertiesFetcher").GetProperties().toString());
Seems it works with that method but not by accessing class member directly.
Try adding corresponding getter methods to the class to see if this helps, e.g.:
public String getVendor() {
return this.Vendor;
}
I get
[ERROR] org.phoenicis.multithreading.ControlledThreadPoolExecutorService (l.64) - TypeError: undefined is not a function
at <js> :anonymous(Unnamed:18:698-727)
at <js> go(Unnamed:81:3209-3243)
at org.graalvm.truffle/com.oracle.truffle.polyglot.ObjectProxyHandler.invoke(HostInteropReflect.java:678)
at com.sun.proxy.$Proxy43.go(Unknown Source)
at org.phoenicis.javafx.components.application.skin.ApplicationInformationPanelSkin.lambda$installScript$7(ApplicationInformationPanelSkin.java:237)
at org.phoenicis.scripts.session.PhoenicisInteractiveScriptSession.eval(PhoenicisInteractiveScriptSession.java:35)
at org.phoenicis.scripts.interpreter.BackgroundScriptInterpreter.lambda$createInteractiveSession$1(BackgroundScriptInterpreter.java:45)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:835)
Exception in thread "pool-3-thread-4" TypeError: undefined is not a function
at <js> :anonymous(Unnamed:18:698-727)
at <js> go(Unnamed:81:3209-3243)
at org.graalvm.truffle/com.oracle.truffle.polyglot.ObjectProxyHandler.invoke(HostInteropReflect.java:678)
at com.sun.proxy.$Proxy43.go(Unknown Source)
at org.phoenicis.javafx.components.application.skin.ApplicationInformationPanelSkin.lambda$installScript$7(ApplicationInformationPanelSkin.java:237)
at org.phoenicis.scripts.session.PhoenicisInteractiveScriptSession.eval(PhoenicisInteractiveScriptSession.java:35)
at org.phoenicis.scripts.interpreter.BackgroundScriptInterpreter.lambda$createInteractiveSession$1(BackgroundScriptInterpreter.java:45)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:835)
when I try to do
.preInstall(function() {
const graphicsProperties = Bean("graphicsPropertiesFetcher").GetProperties();
print(graphicsProperties.getVendor());
print(graphicsProperties.getOpenGLVersion());
print(graphicsProperties.getVulkanVersion());
});
@Zemogiter can you open a PR with your changes. It is quite hard to help debugging this without knowing how exactly your Java code looks :)
wrong person ^^, but the java code is in one of the comment
But
.preInstall(function() {
const graphicsProperties = Bean("graphicsPropertiesFetcher").GetProperties();
print(graphicsProperties.toString());
});
is working correctly?
Yes
Try recompiling again maybe the additional getter methods are not correctly added to the class...
Maybe it is this ? It is not in the toString method.
@madoar Could it be that I call the method on the returned object and not in the call directly ? It is strange that js cannot manage such a simple structure.
Could it be that I call the method on the returned object and not in the call directly ?
What do you mean?
const graphicsProperties = Bean("graphicsPropertiesFetcher").GetProperties();
print(graphicsProperties.getVendor());
vs
print(Bean("graphicsPropertiesFetcher").GetProperties().getVendor());
This should make no difference. There is something going really wrong with the returned object. Can you try:
const graphicsProperties = Bean("graphicsPropertiesFetcher").GetProperties();
print(graphicsProperties);
print(graphicsProperties.getClass());
print(graphicsProperties.getClass().getSimpleName());
and tell us the results?
Intel Open Source Technology Center 3.0 1.1.0
class org.phoenicis.tools.system.GraphicsProperties
GraphicsProperties
Can you try:
print("Methods:");
graphicsProperties.getClass().getDeclaredMethods().foreach(method => {
print(method.getName());
});
print("Fields:");
graphicsProperties.getClass().getDeclaredFields().foreach(field => {
print(field.getName());
});
I got:
Methods:
[ERROR] org.phoenicis.multithreading.ControlledThreadPoolExecutorService (l.64) - TypeError: undefined is not a function
at <js> :anonymous(Unnamed:19-21:719-836)
at <js> go(Unnamed:81:3209-3243)
at org.graalvm.truffle/com.oracle.truffle.polyglot.ObjectProxyHandler.invoke(HostInteropReflect.java:678)
at com.sun.proxy.$Proxy43.go(Unknown Source)
at org.phoenicis.javafx.components.application.skin.ApplicationInformationPanelSkin.lambda$installScript$7(ApplicationInformationPanelSkin.java:237)
at org.phoenicis.scripts.session.PhoenicisInteractiveScriptSession.eval(PhoenicisInteractiveScriptSession.java:35)
at org.phoenicis.scripts.interpreter.BackgroundScriptInterpreter.lambda$createInteractiveSession$1(BackgroundScriptInterpreter.java:45)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:835)
Exception in thread "pool-3-thread-4" TypeError: undefined is not a function
at <js> :anonymous(Unnamed:19-21:719-836)
at <js> go(Unnamed:81:3209-3243)
at org.graalvm.truffle/com.oracle.truffle.polyglot.ObjectProxyHandler.invoke(HostInteropReflect.java:678)
at com.sun.proxy.$Proxy43.go(Unknown Source)
at org.phoenicis.javafx.components.application.skin.ApplicationInformationPanelSkin.lambda$installScript$7(ApplicationInformationPanelSkin.java:237)
at org.phoenicis.scripts.session.PhoenicisInteractiveScriptSession.eval(PhoenicisInteractiveScriptSession.java:35)
at org.phoenicis.scripts.interpreter.BackgroundScriptInterpreter.lambda$createInteractiveSession$1(BackgroundScriptInterpreter.java:45)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:835)
Can you try forEach instead?
Methods:
getVendor
getOpenGLVersion
getVulkan
toString
Fields:
Vendor
OpenGLVersion
VulkanVersion
Then you should be able to access any of these methods and fields from inside JS.
Have you defined GraphicsProperties in its own *.java file or is it an inner class of GraphicsProperties? Can you please move it to its own file.
In addition try using lower-case field names, e.g. vendor, openGLVersion etc.