I am going to write a rendering engine with two back ends. I want to check if the computers hardware for OpenGL support and if it exists load the OpenGL version, if not then load the Java2D version. I have found many examples of how to check for certain extension, but I can't find how to check for hardware OpenGL support! I am sure there's a way to do it, what am I overlooking?
Casey
if (GLContext.getCapabilities().GL11) {
initGL();
} else {
init2D();
DP
Awesome, Thank you!!
GL11 cannot be resolved or is not a field, it does give me a list of extensions that I can check for, but not a wholesale yay or nay. Any other ideas?
mind slip, replace GL11 with OpenGL11
DP
I knew I had to be something simple I was overlooking!! I'll give it a go tomorrow! :wink:
When I do that it kills the JVM. If I replace that condition with a simple true or false, it works fine, so it has to be that line! Any ideas? Here is the error log:
#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00a8d682, pid=2776, tid=3936
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_04-b05 mixed mode)
# Problematic frame:
# j com.sensis.gdm.CanvasFactory.newInstance()Lcom/sensis/gdm/CanvasFactory;+32
#
--------------- T H R E A D ---------------
Current thread (0x00355ea0): JavaThread "main" [_thread_in_Java, id=3936]
siginfo: ExceptionCode=0xc0000005, reading address 0x00001792
Registers:
EAX=0x00000000, EBX=0x00001792, ECX=0x00000000, EDX=0x00000014
ESP=0x0006fa34, EBP=0x0006fa50, ESI=0x27224518, EDI=0x0006fa64
EIP=0x00a8d682, EFLAGS=0x00010246
Top of Stack: (sp=0x0006fa34)
0x0006fa34: 0006fa34 27224518 0006fa64 27224a28
0x0006fa44: 00000000 272245d0 0006fa68 0006fa84
0x0006fa54: 00a829fa 00000000 00000000 00000000
0x0006fa64: 02a9edc0 0006fa68 26fce6d6 0006fa94
0x0006fa74: 27003ad8 00000000 26fce730 0006fa94
0x0006fa84: 0006fab8 00a82923 00000000 02b2b080
0x0006fa94: 02acc280 02acc280 0006fa9c 26fce5ec
0x0006faa4: 0006fac4 27003ad8 00000000 26fce638
Instructions: (pc=0x00a8d682)
0x00a8d672: 44 91 1c 59 c1 e8 1c 83 e0 0f 0f 85 0a 00 00 00
0x00a8d682: 0f be 04 19 50 e9 a4 00 00 00 83 f8 03 0f 85 09
Stack: [0x00030000,0x00070000), sp=0x0006fa34, free space=254k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
j com.sensis.gdm.CanvasFactory.newInstance()Lcom/sensis/gdm/CanvasFactory;+32
j test.FactoryTest.<init>()V+22
j test.FactoryTest.main([Ljava/lang/String;)V+4
v ~StubRoutines::call_stub
V [jvm.dll+0x82696]
V [jvm.dll+0xd6fd9]
V [jvm.dll+0x82567]
V [jvm.dll+0x895e6]
C [javaw.exe+0x14c0]
C [javaw.exe+0x313d]
C [kernel32.dll+0x16d4f]
--------------- P R O C E S S ---------------
Java Threads: ( => current thread )
0x2b289a00 JavaThread "AWT-Windows" daemon [_thread_in_native, id=3400]
0x2b2895d0 JavaThread "AWT-Shutdown" [_thread_blocked, id=3496]
0x2b283d30 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=3940]
0x00a41950 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=1796]
0x00a40528 JavaThread "CompilerThread0" daemon [_thread_blocked, id=180]
0x00a3f8b0 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=3476]
0x00a36b58 JavaThread "Finalizer" daemon [_thread_blocked, id=3644]
0x009e9b30 JavaThread "Reference Handler" daemon [_thread_blocked, id=3216]
=>0x00355ea0 JavaThread "main" [_thread_in_Java, id=3936]
Other Threads:
0x00a32bb0 VMThread [id=3032]
0x00a42b28 WatcherThread [id=3888]
VM state:not at safepoint (normal execution)
VM Mutex/Monitor currently owned by a thread: None
Heap
def new generation total 41088K, used 2200K [0x02a80000, 0x05710000, 0x05710000)
eden space 36544K, 6% used [0x02a80000, 0x02ca6310, 0x04e30000)
from space 4544K, 0% used [0x04e30000, 0x04e30000, 0x052a0000)
to space 4544K, 0% used [0x052a0000, 0x052a0000, 0x05710000)
tenured generation total 548288K, used 0K [0x05710000, 0x26e80000, 0x26e80000)
the space 548288K, 0% used [0x05710000, 0x05710000, 0x05710200, 0x26e80000)
compacting perm gen total 8192K, used 4177K [0x26e80000, 0x27680000, 0x2ae80000)
the space 8192K, 50% used [0x26e80000, 0x27294558, 0x27294600, 0x27680000)
No shared spaces configured.
Dynamic libraries:
0x00400000 - 0x0040c000 C:\Program Files\Java\jre1.5.0_04\bin\javaw.exe
0x7c900000 - 0x7c9b0000 C:\WINDOWS\system32\ntdll.dll
0x7c800000 - 0x7c8f4000 C:\WINDOWS\system32\kernel32.dll
0x77dd0000 - 0x77e6b000 C:\WINDOWS\system32\ADVAPI32.dll
0x77e70000 - 0x77f01000 C:\WINDOWS\system32\RPCRT4.dll
0x77d40000 - 0x77dd0000 C:\WINDOWS\system32\USER32.dll
0x77f10000 - 0x77f56000 C:\WINDOWS\system32\GDI32.dll
0x77c10000 - 0x77c68000 C:\WINDOWS\system32\MSVCRT.dll
0x6d640000 - 0x6d7c9000 C:\Program Files\Java\jre1.5.0_04\bin\client\jvm.dll
0x76b40000 - 0x76b6d000 C:\WINDOWS\system32\WINMM.dll
0x6d280000 - 0x6d288000 C:\Program Files\Java\jre1.5.0_04\bin\hpi.dll
0x76bf0000 - 0x76bfb000 C:\WINDOWS\system32\PSAPI.DLL
0x6d610000 - 0x6d61c000 C:\Program Files\Java\jre1.5.0_04\bin\verify.dll
0x6d300000 - 0x6d31d000 C:\Program Files\Java\jre1.5.0_04\bin\java.dll
0x6d630000 - 0x6d63f000 C:\Program Files\Java\jre1.5.0_04\bin\zip.dll
0x6d000000 - 0x6d167000 C:\Program Files\Java\jre1.5.0_04\bin\awt.dll
0x73000000 - 0x73026000 C:\WINDOWS\system32\WINSPOOL.DRV
0x76390000 - 0x763ad000 C:\WINDOWS\system32\IMM32.dll
0x774e0000 - 0x7761d000 C:\WINDOWS\system32\ole32.dll
0x73760000 - 0x737a9000 C:\WINDOWS\system32\ddraw.dll
0x73bc0000 - 0x73bc6000 C:\WINDOWS\system32\DCIMAN32.dll
0x73940000 - 0x73a10000 C:\WINDOWS\system32\D3DIM700.DLL
0x6d240000 - 0x6d27d000 C:\Program Files\Java\jre1.5.0_04\bin\fontmanager.dll
0x74720000 - 0x7476b000 C:\WINDOWS\system32\MSCTF.dll
0x7c9c0000 - 0x7d1d4000 C:\WINDOWS\system32\shell32.dll
0x77f60000 - 0x77fd6000 C:\WINDOWS\system32\SHLWAPI.dll
0x773d0000 - 0x774d2000 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll
0x5d090000 - 0x5d127000 C:\WINDOWS\system32\comctl32.dll
0x2b570000 - 0x2b5b1000 C:\WINDOWS\SYSTEM32\lwjgl.dll
0x72280000 - 0x722aa000 C:\WINDOWS\system32\DINPUT.dll
0x5ed00000 - 0x5edcc000 C:\WINDOWS\system32\OPENGL32.dll
0x68b20000 - 0x68b40000 C:\WINDOWS\system32\GLU32.dll
0x77c00000 - 0x77c08000 C:\WINDOWS\system32\VERSION.dll
VM Arguments:
jvm_args: -Xms580m -Xmx580m
java_command: test.FactoryTest
Environment Variables:
PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\matlab6p5p1\bin\win32;C:\Program Files\Common Files\Autodesk Shared\
USERNAME=cborders
OS=Windows_NT
PROCESSOR_IDENTIFIER=x86 Family 15 Model 4 Stepping 1, GenuineIntel
--------------- S Y S T E M ---------------
OS: Windows XP Build 2600 Service Pack 2
CPU:total 1 family 15, cmov, cx8, fxsr, mmx, sse, sse2, ht
Memory: 4k page, physical 1038408k(508088k free), swap 1712236k(664764k free)
vm_info: Java HotSpot(TM) Client VM (1.5.0_04-b05) for windows-x86, built on Jun 3 2005 02:10:41 by "java_re" with MS VC++ 6.0
[/code]
Heh. The problem here is that GLContext.getCapabilities() is null, since it is only initialized when a context is active. The right way to check for OpenGL is to create the Display or a Pbuffer.
However, even a null ContextCapabilities reference should not result in a native crash, so I investigated further and it seems that CaseyB has run into a JVM bug! To verify that it really is a JVM bug, I've created a somewhat minimal test case that can be found here:
http://odense.kollegienet.dk/~naur/JVMCrash.zip
it contains a stand alone cut down version of ContextCapabilities and a JVMCrash.java that looks like this:
public class JVMCrash {
public static void main(String[] args) {
ContextCapabilities f = null;
System.out.println("f = " + f + " | f.OpenGL11 = " + f.OpenGL11);
}
}
The test contains no native code, so it is proof that this is a JVM bug. The bug seems to be caused by large classes, since deleting fields from the ContextCapabilities class will make the native crash disappear and result in the expected NullPointerException.
I'll post a bug to sun.
- elias
This bug is probably caused by us exceeding the 64kb limit on class file size. ContextCapabilities is 90-odd kb. I should think that it's not checked properly on local class loads (ie. the verifier is not turned on) and this might lead to some unexpected behaviour.
Cas :)
I downloaded the newest snapshot of 6.0 and it's broken there too! If it is a class size restriction issue is there a way around it??
-=EDIT=-
I googled "LWJGL Pbuffer" and found some very useful code by gregorypierce that lets me check for the support I need!! Thank you guys!
Don't use the getCapabilities check. The correct way to check for OpenGL support is to try to create a Display or a Pbuffer.
- elias
so it would be:
Pbuffer pbuffer = new Pbuffer(1, 1, new PixelFormat(), null, null);
if(pbuffer != null)
{
// OpenGL
}
else
{
// Java2D
}
You see the trouble that I'm having is that I don't have an OpenGL-less computer to test this on, so I don't know if it will simply not create the pbuffer or if it will crash most egregiously!
Further investigation reveals that the class size itself is not the issue but the size of some part of the class file; in this case I think we're using more than 64kb for the constant pool because of all those variables.
Cas :)
If it crashes, it's a lwjgl bug and you should report it :). But why not simply create the Display right away, and if it fails, fall back to Java2D? It seems wasteful to create a Pbuffer just the check if the Display can be created (assuming you want to display something, not just do offline rendering).
Besides, Pbuffer creation can fail where Display creation succeeds. For example when the OpenGL drivers doesn't support Pbuffers. However, if you keep the Pbuffer check, remember to destroy it again.
- elias
I am using an AWTGLCanvas as part of a larger app, so I am writing classes that extend java.awt.Canvas and AWTGLCanvas and loading the correct one depending on the results of the test!
Test by creating the AWTGLCanvas then?
- elias
Ok, I found an old P2 350MHz that has an integrated video card with no OpenGL support! I tried loading the OpenGL version of my class that used the AWTGLCanvas and it loaded without an error, but it puked on the first paint! So I went back to using the Pbuffer. What happened there was that when it tried to create the Pbuffer it would throw and exception so I just caught that and used that to decide to load the Java2D version. Here is my code for that part:
try
{
System.out.println("Trying OpenGL");
try
{
Pbuffer buff = new Pbuffer(1, 1, new PixelFormat(), null, null);
if (classLoader == null)
{
theClass = Class.forName(openGL);
}
else
{
theClass = classLoader.loadClass(openGL);
}
System.out.println("OpenGL Succeeded");
buff.destroy();
}
catch(ExceptionInInitializerError eiie)
{
System.out.println("OpenGL Failed\nTrying Java2D");
if (classLoader == null)
{
theClass = Class.forName(java2D);
}
else
{
theClass = classLoader.loadClass(java2D);
}
System.out.println("Java2D Succeeded");
}
}
catch (ClassNotFoundException cnfe)
{
throw cnfe;
}
It seems to me that by doing it this way (trying to create a Display or PBuffer), you're still missing out on what capabilities are available. For instance, what if I want to use GL15 instead of GL11? Is this something that has been bugged for LWJGL or are we just out of luck?
Once you create an OpenGL context you should be able to test for an OpenGL 1.5 feature and decide based on that.
*Confused* I thought it was just decided that the getCapabilities() method causes a JVM crash? Or is there another method that I'm missing?
Oh... are you saying that I should create the Display first, and then call getCapabilities() on the newly created GLContext? Perhaps I misinterpreted what the original problem was...
Quote from: "Whackjack"are you saying that I should create the Display first, and then call getCapabilities() on the newly created GLContext?
Exactly! The problem that I was having was that I couldn't be sure that the client machine had an OpenGL capable graphics card so I just wanted to test for OpenGL 1.1 compatability. In order to do the
getCapabilities() test you need an existing OpenGL context. So you should perform the check on an existing Display... unless I have totally gone off my rocker! :)
Thanks, CaseyB... That does make sense, even if it's a little backwards. I guess I was thinking along the lines you were in that you could test for OpenGL compatibility before trying to create anything.
I'll keep this in my mind for future reference. Thanks again!
The bug in the JVM has been resolved in Mustang b62:
Quote
6342951 Implicit null checks on large objects cause JVM crash
That was quick, I expected a 3 year wait atleast! :roll:
Edit: 1.5.0_7 seems to have the update too...everybody update!
DP
Quote from: "darkprophet"The bug in the JVM has been resolved in Mustang b62:
Quote
6342951 Implicit null checks on large objects cause JVM crash
That was quick, I expected a 3 year wait atleast! :roll:
Edit: 1.5.0_7 seems to have the update too...everybody update!
DP
Nah, anything else than ASAP would have been strange, since this bug is a sure way to issue DOS attacks on a running (shared) JVM.
- elias