summaryrefslogtreecommitdiffstats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* Fixed several more places in code with same error as in Issue 292Kenneth Russel2007-04-191-12/+12
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1203 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 292: gluScaleImage does not scale correctly Kenneth Russel2007-04-192-27/+27
| | | | | | | | Conversion scale factors for x and y dimensions were flipped. Also adjusted Image.fill_image() so code does not assert. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1202 232f8b59-042b-4e1e-8c03-345bb8c30851
* Reverted TextRenderer back to not tokenizing strings as that wasn't Kenneth Russel2007-04-181-6/+6
| | | | | | | producing identical rendering results git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1200 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 290: GLJPanel throws NullPointerExceptions with Java 2D/JOGL bridge Kenneth Russel2007-04-171-2/+10
| | | | | | | | | | Fixed NPEs in setAutoSwapBufferMode and swapBuffers if Java 2D / JOGL bridge is enabled. These methods are essentially no-ops on the GLJPanel anyway because of how the copying to the Swing rendering area (be it a BufferedImage or the Swing back buffer) is done. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1199 232f8b59-042b-4e1e-8c03-345bb8c30851
* More fully debugged tokenized rendering of strings and turned it on by Kenneth Russel2007-04-081-13/+19
| | | | | | | | default. Can be disabled by specifying -Djogl.TextRenderer.nosplit. Exposed getSpaceWidth() on request of emzic on javagaming.org forums. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1195 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added automatic mipmap generation support via GL_GENERATE_MIPMAP Kenneth Russel2007-04-083-22/+179
| | | | | | | | | | texture parameter to Texture class. Exposed this support up through the TextureRenderer and TextRenderer classes. Tested by temporarily enabling mipmap support for TextCube demo; no visual improvement, however, so left it disabled for now. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1194 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed problem pointed out by user operator on JOGL forum where chosen Kenneth Russel2007-04-071-1/+16
| | | | | | | | GLCapabilities on Windows was returning null for pixel formats using full-scene antialiasing git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1193 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added TextureIO.setTexRectEnabled() and isTexRectEnabled() based onKenneth Russel2007-04-032-1/+38
| | | | | | | | discussions with Chris Campbell of the Java 2D team, and changed Texture implementation to respect it git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1190 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added a markDirty() method to TextureRenderer and removed the sync() Kenneth Russel2007-03-273-25/+62
| | | | | | | | | | | method. markDirty() may be called at an arbitrary point (in particular, when no OpenGL context is current) and the union of the dirty regions is automatically synced with the underlying texture during the next getTexture() operation, at which point the dirty region is cleared. Adjusted Overlay and TextRenderer classes. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1182 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added Texture.getAspectRatio().Kenneth Russel2007-03-211-0/+13
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1177 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 274: GLException when GLJPanel (initially not visible) is made ↵Kenneth Russel2007-03-211-0/+33
| | | | | | | | | | | | | | | | | | | | | | | | | visible/showing Investigation revealed that the symptom was similar to what happens when one tries to create a new OpenGL context against an invalid HDC on Windows. Discussion with Chris Campbell from the Java 2D team indicated that in situations where the Java 2D OpenGL pipeline is using Frame Buffer Objects for its rendering, it is possible that its internal OpenGL context can be left current to the on-screen drawable, and it only has a valid device context for the brief period of time when its OpenGL context was being made current. This means that by the time JOGL's code got a chance to run, it did not have a valid HDC and therefore could not create its OpenGL context against it. The workaround, suggested by Chris, is to forcibly make the Java 2D context current against its internal "scratch" pbuffer, which can be done with the internal invokeWithOGLSharedContextCurrent method. Added this workaround and verified it fixes the problem with the user's test case. This issue will be fixed in a forthcoming Java SE 6 update release, hopefully 6u2. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1176 232f8b59-042b-4e1e-8c03-345bb8c30851
* Simplified math in last putbackKenneth Russel2007-03-161-2/+2
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1171 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 287: TextRenderer rendering artifacts Kenneth Russel2007-03-161-3/+17
| | | | | | | | | | Stress testing uncovered that when neither GL_ARB_texture_non_power_of_two or GL_ARB_texture_rectangle were available, the Texture class was returning incorrect texture coordinates for textures which needed to be flipped vertically. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1170 232f8b59-042b-4e1e-8c03-345bb8c30851
* Made disabling of the depth test optional in TextRenderer and Kenneth Russel2007-02-272-12/+63
| | | | | | | | TextureRenderer's orthographic rendering methods based on feedback from Dave Collins from NASA World Wind project git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1160 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 281: FileUtil doc enhancement Kenneth Russel2007-02-271-4/+12
| | | | | | | Improved documentation as suggested. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1159 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 277: Documentation enhancement Kenneth Russel2007-02-271-36/+66
| | | | | | | | Added text to Screenshot class's methods indicating which read buffer is used. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1157 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 278: Fatal error when rendering text Kenneth Russel2007-02-272-1/+42
| | | | | | | | | Added code to restore current text drawing color when backing store is resized. Fixed NullPointerException in RectanglePacker during deletion if no backing store was allocated. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1156 232f8b59-042b-4e1e-8c03-345bb8c30851
* On advice from Chris Campbell, forced TYPE_INT_ARGB and Kenneth Russel2007-02-271-3/+12
| | | | | | | | | | TYPE_4BYTE_ABGR images down custom code path in order to obey general invariant that image data sent down to OpenGL has premultiplied alpha. Fixed bug in handling of TYPE_INT_ARGB images in custom image conversion. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1155 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed issue with parsing of OpenGL version strings pointed out byKenneth Russel2007-02-271-5/+6
| | | | | | | TimLambert on javagaming.org forum git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1154 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 276: Bug in handling of RGB-like custom BufferedImages in TextureIO Kenneth Russel2007-02-221-1/+1
| | | | | | | | | Code path handling RGB-like TYPE_CUSTOM BufferedImages in the TextureIO classes should have been computing the row length by dividing the scanline stride by 3, not 4. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1150 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 275: Rendering bugs in TextRenderer Kenneth Russel2007-02-221-1/+38
| | | | | | | | | | | | | Fixed problem where during resizing of backing store for TextRenderer we were neglecting to unbind the old texture and bind the new one. This caused attempts to render with an invalid texture, which was probably the cause of crashes and definitely the cause of rendering artifacts. Fixed by calling endRendering() / beginRendering() appropriately on the underlying TextureRenderer during resizing of the backing store of the TextRenderer. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1148 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 273: class DDSImage don't support cubemap textures Kenneth Russel2007-02-211-16/+144
| | | | | | | Incorporated suggested fix from java.net user bandures. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1146 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 272: Move setColor method from TextRenderer up to TextureRenderer Kenneth Russel2007-02-202-28/+64
| | | | | | | | Moved setColor() implementation from TextRenderer to TextureRenderer and reimplemented TextRenderer's methods in terms of it. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1143 232f8b59-042b-4e1e-8c03-345bb8c30851
* Addendum to fix for Issue 271: wglGetPixelFormatAttribivARB() fails forcing ↵Kenneth Russel2007-02-201-1/+1
| | | | | | | | | | software OpenGL Conditionalized one more debug-only use of a multisample-related query. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1142 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 271: wglGetPixelFormatAttribivARB() fails forcing software OpenGL Kenneth Russel2007-02-201-4/+8
| | | | | | | | | | New code added for support of getChosenGLCapabilities() was causing errors described in bug report. Conditionalized querying of multisample properties based on availability of WGL_ARB_multisample extension. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1141 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added handling and documentation for jogl.silent.noddraw.check and Kenneth Russel2007-02-141-26/+61
| | | | | | | | | jogl.disable.noddraw.check applet parameters on request of NASCAR RaceView team at Turner Broadcasting. Forced inclusion of current JRE's version in version set for better robustness. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1132 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added RenderDelegate mechanism to TextRenderer to provide more control Kenneth Russel2007-02-111-19/+103
| | | | | | | | where desired over the rendered text bitmap. Added CustomText demo to demonstrate its usage. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1128 232f8b59-042b-4e1e-8c03-345bb8c30851
* Javadoc fixKenneth Russel2007-02-111-2/+3
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1127 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added setColor(Color) convenience methodKenneth Russel2007-02-111-0/+16
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1126 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 267: class DDSImage return incorrect mipmap level data. Kenneth Russel2007-01-261-2/+2
| | | | | | | Applied recommended fix from submitter. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1107 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added GL_TEXTURE_BIT and GL_COLOR_BUFFER_BIT to set of attributes Kenneth Russel2007-01-251-1/+2
| | | | | | | | pushed / popped by TextureRenderer on suggestion of Tom Gaskins and Chris Campbell git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1104 232f8b59-042b-4e1e-8c03-345bb8c30851
* Removed incorrect comment about alpha bits pointed out by Chris CampbellKenneth Russel2007-01-251-3/+1
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1103 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 264: SecurityException in JOGLAppletLauncher if JOAL not present Kenneth Russel2007-01-221-1/+5
| | | | | | | | Made JOGLAppletLauncher more robust to exceptions thrown from Class.forName() looking up AL.class. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1098 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 263: JOGL applets slow in Mozilla / FirefoxKenneth Russel2007-01-221-0/+9
| | | | | | | | | Added documentation to JOGLAppletLauncher indicating that Talkback agent is responsible for slowdown of JOGL-based applets and provided instructions on how to turn it off. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1097 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 262: DRIHack problems with ATI and possibly other driversKenneth Russel2007-01-211-7/+2
| | | | | | | | | | | Added support to GlueGen's NativeLibrary class for relative library path names which do not require expansion; for example, "libGL.so.1". Changed the DRIHack to first attempt to open libGL.so.1 instead of "GL", which expanded to "libGL.so". For some reason, this causes ATI's drivers to be picked up properly. Tested with various JOGL demos. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1093 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added 3D rendering methods to TextureRenderer and TextRenderer on Kenneth Russel2007-01-202-90/+230
| | | | | | | | | | | | request of several people on javagaming.org forums. Refactored existing 2D rendering support in these classes in terms of the new 3D methods. Wrote new TextCube demo illustrating how to render 2D text in 3D using the TextRenderer. Factored out FPS counter rendering into new FPSCounter utility class and updated TestTextRenderer and FlyingText demos. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1092 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 260: "GLException: Surface already locked" after failed makeCurrent Kenneth Russel2007-01-173-12/+21
| | | | | | | | | Added checking for thrown run-time exceptions to on-screen GLContext makeCurrent() implementations on all three major supported platforms; now unlocks the underlying GLDrawable if an exception is thrown. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1088 232f8b59-042b-4e1e-8c03-345bb8c30851
* Robustness improvements to TextRenderer and underlying RectanglePacker. Kenneth Russel2007-01-135-84/+450
| | | | | | | | | | | | | | | Added ability to specify a maximum size to which the RectanglePacker can expand. Added preExpand method to BackingStoreManager to support early eviction of unused entries instead of always expanding the backing store, and additionFailed method used when the backing store can not expand further. Added more robust free list coalescing to Level. Added support for shrinking of backing store and for eager compaction when there is a lot of vertical dead space. Added TextFlow demo which shows how to do dynamic layout of text and which acts as a stress test for the TextRenderer. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1083 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added -Djogl.drihack.disable for manual disabling of DRI hackKenneth Russel2007-01-111-0/+5
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1080 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 259: need a copy context Kenneth Russel2007-01-075-0/+83
| | | | | | | | | | Added and specified GLContext.copy() and supplied implementations on Windows, X11 and Mac OS X platforms. New code is untested at this time. May need to make subsequent changes on X11 and Mac platforms where new code has not been compiled yet. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1075 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added new FlyingText demo to illustrate more advanced usage of the Kenneth Russel2007-01-072-15/+34
| | | | | | | | | | | TextRenderer class; displays dynamically rotated, translated and colored text. Changed how setSmoothing() is handled by the TextureRenderer and stopped disabling smoothing in the TextRenderer. For the time being, not exposing this flag in that class to keep the API simple. Changed TextRenderer to also push/pop the texture matrix. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1073 232f8b59-042b-4e1e-8c03-345bb8c30851
* With help from Chris Campbell, fixed incredibly stupid bug on my part Kenneth Russel2007-01-063-1/+47
| | | | | | | | | | | | | | | | where the new Java 2D TextureRenderer was destroying and re-creating the OpenGL texture every frame. This was why the Java 2D Overlay class was so expensive, and why the TextRenderer wasn't as fast as it seemed it should be. Fixed bugs in all of the Java 2D demos which were covered up by this implicit sync, as well as in the TextRenderer class itself where it was missing a key sync operation. Added code to the Texture.updateSubImage() implementation to clip the incoming rectangle to the bounds of the input data and texture, to keep OpenGL from dropping almost-valid updates on the floor. Ran all of the Java 2D integration demos to verify these fixes. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1071 232f8b59-042b-4e1e-8c03-345bb8c30851
* With extensive help from Phil Race and Chris Campbell from the Java 2D Kenneth Russel2007-01-049-5/+1476
| | | | | | | | | | | | | | | | | | | | | | team, added a TextRenderer class which enables high-performance rendering of bitmapped Java 2D fonts, with full Unicode support, into arbitrary OpenGL drawables using a simple API. Builds on top of the TextureRenderer class and its associated functionality; added createAlphaOnlyRenderer() and other methods to enable the TextRenderer. Caches rendering results on a string-by-string basis in an OpenGL texture using a fully automatic least-recently-used algorithm for good efficiency when rendering the same string or strings multiple times. Uses a rectangle packing algorithm, currently housed in com.sun.opengl.impl.packrect, for managing the positions of cached strings on a larger OpenGL texture to avoid OpenGL pipeline state changes. Added a TestTextRenderer demo which simply adds a moving text string and frames-per-second counter to the Gears demo; more sophisticated examples to come. (Some commented-out debugging code is being temporarily left in the new demo, to be removed in the next checkin, in order to have it in the version history.) git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1067 232f8b59-042b-4e1e-8c03-345bb8c30851
* Moved J2DTextureRenderer and J2DOverlay into their own sub-package and Kenneth Russel2007-01-042-11/+11
| | | | | | | | | dropped the prefixes on the suggestion of Chris Campbell. No other changes to these classes. Added com.sun.opengl.util.j2d to the javadoc generation. Updated demos. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1066 232f8b59-042b-4e1e-8c03-345bb8c30851
* Added getImage() and simpler drawOrthoRect() helper method on Kenneth Russel2007-01-041-0/+25
| | | | | | | suggestion of Chris Campbell git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1065 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixes for building with Visual Studio .NET 2003 (Service Pack 1)Kenneth Russel2007-01-031-2/+2
| | | | git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1063 232f8b59-042b-4e1e-8c03-345bb8c30851
* On request from James Gosling and others, added a J2DTextureRenderer Kenneth Russel2006-12-302-0/+559
| | | | | | | | | | | | | | | | | | class to com.sun.opengl.util to make it easier to render into OpenGL textures using Java 2D. Added convenience methods to this class to make it easy to draw sub-rectangles of the resulting texture to the screen. Added a J2DOverlay class which acts like a Java 2D-based heads-up display for an arbitrary GLDrawable, tracking its size and making it easier to render the entire contents of the HUD. There appear to be performance issues with the J2DOverlay class as the window gets large, at least on older hardware, as it allocates very large OpenGL textures internally. Added tests for both the J2DTextureRenderer and J2DOverlay classes which have similar functionality but different implementation approaches and different performance characteristics. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1059 232f8b59-042b-4e1e-8c03-345bb8c30851
* Fixed Issue 257: RFE: Texture.updateSubImage(x,y,w,h) Kenneth Russel2006-12-292-143/+233
| | | | | | | | | | | | | | | | | | | | Changed TextureIO's BufferedImage code paths to no longer copy the data in order to correct for the vertical flip needed between Java 2D's and OpenGL's coordinate systems, but instead to correct for this using a flip of the texture coordinates. This was needed to change the semantics for the BufferedImage from "by-copy" to "by-reference". Made the custom BufferedImage copying code path occur lazily upon a call to TextureData.getBuffer(). Added support for the GL_EXT_abgr extension but disabled the code path currently as it appears there may be bugs in its support on some drivers. Added computation of row width for all BufferedImage types with help and suggestions from Chris Campbell. Improved handling of some BufferedImage types like TYPE_INT_ARGB and TYPE_4BYTE_ABGR. Added Texture.updateSubImage() taking a source rectangle as well as a destination coordinate. Wrote TestSubImage test to show use of the new API which exercises all BufferedImage types. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1057 232f8b59-042b-4e1e-8c03-345bb8c30851
* Worked around breakage of JOGL with 5.0u10: see Sun bug IDs Kenneth Russel2006-12-221-1/+2
| | | | | | | 6504460 and 6333613 git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1047 232f8b59-042b-4e1e-8c03-345bb8c30851
* Updated javadoc for JOGLAppletLauncher to document JOAL support, new Kenneth Russel2006-12-221-21/+46
| | | | | | | | library and native library jar structure, and to remove comment on bug with multiple JOGL applets on the same web page, which has been fixed git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1040 232f8b59-042b-4e1e-8c03-345bb8c30851
> 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
/*
 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
 * Copyright (c) 2010 JogAmp Community. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed or intended for use
 * in the design, construction, operation or maintenance of any nuclear
 * facility.
 */

package javax.media.opengl;

import jogamp.nativewindow.NWJNILibLoader;
import jogamp.opengl.Debug;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLDrawableFactoryImpl;
import jogamp.opengl.DesktopGLDynamicLookupHelper;

import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.jvm.JNILibLoaderBase;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.common.util.VersionUtil;
import com.jogamp.common.util.cache.TempJarCache;
import com.jogamp.common.util.locks.LockFactory;
import com.jogamp.common.util.locks.RecursiveThreadGroupLock;
import com.jogamp.nativewindow.NativeWindowVersion;
import com.jogamp.opengl.JoglVersion;

import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowFactory;
import javax.media.opengl.fixedfunc.GLPointerFunc;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * Specifies the the OpenGL profile.
 * 
 * This class static singleton initialization queries the availability of all OpenGL Profiles
 * and instantiates singleton GLProfile objects for each available profile.
 *
 * The platform default profile may be used, using {@link GLProfile#GetProfileDefault()}, 
 * or more specialized versions using the other static GetProfile methods.
 */
public class GLProfile {
    
    public static final boolean DEBUG = Debug.debug("GLProfile");
    
    static {
        // Also initializes TempJarCache if shall be used.
        Platform.initSingleton();
    }
    
    /**
     * Static initialization of JOGL.
     *
     * <p>
     * This method shall not need to be called for other reasons than having a defined initialization sequence.
     * </p>
     * 
     * <P>
     * In case this method is not invoked, GLProfile is initialized implicit by
     * the first call to {@link #getDefault()}, {@link #get(java.lang.String)}.
     * <P>
     * 
     * <p>
     * To initialize JOGL at startup ASAP, this method may be invoked in the <i>main class</i>'s 
     * static initializer block, in the <i>static main() method</i> or in the <i>Applet init() method</i>.
     * </p>
     * 
     * <p>
     * Since JOGL's initialization is complex and involves multi threading, it is <b>not</b> recommended
     * to be have it invoked on the AWT EDT thread. In case all JOGL usage is performed 
     * on the AWT EDT, invoke this method outside the AWT EDT - see above.
     * </p>
     * 
     */
    public static void initSingleton() {
        final boolean justInitialized; 
        initLock.lock();
        try {
            if(!initialized) { // volatile: ok
                initialized = true;
                justInitialized = true;
                if(DEBUG) {
                    System.err.println("GLProfile.initSingleton() - thread "+Thread.currentThread().getName());
                    Thread.dumpStack();
                }
    
                // run the whole static initialization privileged to speed up,
                // since this skips checking further access
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        Platform.initSingleton();
                        
                        // Performance hack to trigger classloading of the GL classes impl, which makes up to 12%, 800ms down to 700ms
                        new Thread(new Runnable() {
                          public void run() {
                              final ClassLoader cl = GLProfile.class.getClassLoader();
                              try {
                                  ReflectionUtil.createInstance(getGLImplBaseClassName(GL4bc)+"Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { null, null }, cl);
                              } catch (Throwable t) {}
                              try {
                                  ReflectionUtil.createInstance(getGLImplBaseClassName(GLES2)+"Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { null, null }, cl);              
                              } catch (Throwable t) {}
                              try {
                                  ReflectionUtil.createInstance(getGLImplBaseClassName(GLES1)+"Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { null, null }, cl);              
                              } catch (Throwable t) {}
                          }
                        }, "GLProfile-GL_Bootstrapping").start();      

                        
                        if(TempJarCache.isInitialized()) {
                           final ClassLoader cl = GLProfile.class.getClassLoader();
                           // either: [jogl-all.jar, jogl-all-noawt.jar, jogl-all-mobile.jar] -> jogl-all-natives-<os.and.arch>.jar
                           // or:     nativewindow-core.jar                                   -> nativewindow-natives-<os.and.arch>.jar,
                           //         jogl-core.jar                                           -> jogl-natives-<os.and.arch>.jar,
                           //        (newt-core.jar                                           -> newt-natives-<os.and.arch>.jar)? (if available)
                           final String newtFactoryClassName = "com.jogamp.newt.NewtFactory";
                           final Class<?>[] classesFromJavaJars = new Class<?>[] { NWJNILibLoader.class, GLProfile.class, null };
                           if( ReflectionUtil.isClassAvailable(newtFactoryClassName, cl) ) {
                               classesFromJavaJars[2] = ReflectionUtil.getClass(newtFactoryClassName, false, cl);
                           }
                           JNILibLoaderBase.addNativeJarLibs(classesFromJavaJars, "-all", new String[] { "-noawt", "-mobile", "-core" } );
                        }
                        initProfilesForDefaultDevices();
                        return null;
                    }
                });
            } else {
                justInitialized = false;
            }
        } finally {
            initLock.unlock();
        }
        if(DEBUG) {
            if( justInitialized && ( hasGL234Impl || hasGLES1Impl || hasGLES2Impl ) ) {
                System.err.println(JoglVersion.getDefaultOpenGLInfo(defaultDevice, null, true));
            }
        }        
    }
    
    /**
     * Trigger eager initialization of GLProfiles for the given device,
     * in case it isn't done yet.
     * 
     * @throws GLException if no profile for the given device is available.
     */
    public static void initProfiles(AbstractGraphicsDevice device) throws GLException {
        getProfileMap(device, true);
    }

    /**
     * Manual shutdown method, may be called after your last JOGL use
     * within the running JVM.<br>
     * It releases all temporary created resources, ie issues {@link javax.media.opengl.GLDrawableFactory#shutdown()}.<br>
     * The shutdown implementation is called via the JVM shutdown hook, if not manually invoked.<br>
     * <p>
     * This method shall not need to be called for other reasons than issuing a proper shutdown of resources at a defined time.
     * </p>
     */
    public static void shutdown() {
        initLock.lock();
        try {
            if(initialized) { // volatile: ok
                initialized = false;
                if(DEBUG) {
                    System.err.println("GLProfile.shutdown() - thread "+Thread.currentThread().getName());
                    Thread.dumpStack();
                }                    
                GLDrawableFactory.shutdown();
            }
        } finally {
            initLock.unlock();
        }
    }

    //
    // Query platform available OpenGL implementation
    //

    /** 
     * Returns the availability of a profile on a device.
     * 
     * @param device a valid AbstractGraphicsDevice, or <code>null</null> for the default device.
     * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), 
     *        or <code>[ null, GL ]</code> for the default profile.
     * @return true if the profile is available for the device, otherwise false.
     */
    public static boolean isAvailable(AbstractGraphicsDevice device, String profile) {
        initSingleton();
        return isAvailableImpl(getProfileMap(device, false), profile);
    }
    private static boolean isAvailableImpl(HashMap<String /*GLProfile_name*/, GLProfile> map, String profile) {
        return null != map && null != map.get(profile);
    }
    
    /** 
     * Returns the availability of a profile on the default device.
     * 
     * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), 
     *        or <code>[ null, GL ]</code> for the default profile.
     * @return true if the profile is available for the default device, otherwise false.
     */
    public static boolean isAvailable(String profile) {
        return isAvailable(null, profile);
    }
    
    /** 
     * Returns the availability of any profile on the default device.
     * 
     * @return true if any profile is available for the default device, otherwise false.
     */
    public static boolean isAnyAvailable() {
        return isAvailable(null, null);
    }
    
    public static String glAvailabilityToString(AbstractGraphicsDevice device) {
        return glAvailabilityToString(device, null).toString();
    }
    
    public static StringBuilder glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb) {
        return glAvailabilityToString(device, sb, null, 0);
    }
    private static StringBuilder doIndent(StringBuilder sb, String indent, int indentCount) {
        while(indentCount>0) {
            sb.append(indent);
            indentCount--;
        }
        return sb;
    }
    public static StringBuilder glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb, String indent, int indentCount) {
        boolean avail;
        if(null == sb) {
            sb = new StringBuilder();
        }
        final boolean useIndent = null != indent;

        initSingleton();
        
        if(null==device) {
            device = defaultDevice;
        }
        final HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device, false);
        
        if(useIndent) {
            doIndent(sb, indent, indentCount).append("Native");
            indentCount++;
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL4bc").append(indent);
        } else {
            sb.append("Native[GL4bc ");
        }        
        avail=isAvailableImpl(map, GL4bc);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 4, GLContext.CTX_PROFILE_COMPAT);
        }

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL4").append(indent);
        } else {
            sb.append(", GL4 ");
        }
        avail=isAvailableImpl(map, GL4);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 4, GLContext.CTX_PROFILE_CORE);
        }

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL3bc").append(indent);
        } else {
            sb.append(", GL3bc ");
        }
        avail=isAvailableImpl(map, GL3bc);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_COMPAT);
        }

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL3").append(indent);
        } else {
            sb.append(", GL3 ");
        }
        avail=isAvailableImpl(map, GL3);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_CORE);
        }

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL2").append(indent);
        } else {
            sb.append(", GL2 ");
        }
        avail=isAvailableImpl(map, GL2);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 2, GLContext.CTX_PROFILE_COMPAT);
        }

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL2ES1").append(indent);
        } else {
            sb.append(", GL2ES1 ");
        }
        sb.append(isAvailableImpl(map, GL2ES1));

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GLES1").append(indent);
        } else {
            sb.append(", GLES1 ");
        }
        avail=isAvailableImpl(map, GLES1);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 1, GLContext.CTX_PROFILE_ES);
        }

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL2ES2").append(indent);
        } else {
            sb.append(", GL2ES2 ");
        }
        sb.append(isAvailableImpl(map, GL2ES2));

        if(useIndent) {
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GLES2").append(indent);
        } else {
            sb.append(", GLES2 ");
        }
        avail=isAvailableImpl(map, GLES2);
        sb.append(avail);
        if(avail) {
            glAvailabilityToString(device, sb.append(" "), 2, GLContext.CTX_PROFILE_ES);
        }

        if(useIndent) {
            indentCount--;
            doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("Profiles");
            indentCount++;
        } else {
            sb.append("], Profiles[");
        }
        
        if(null != map) {
            for(Iterator<GLProfile> i=map.values().iterator(); i.hasNext(); ) {
                if(useIndent) {
                    doIndent(sb.append(Platform.getNewline()), indent, indentCount);
                }
                sb.append(i.next().toString());
                if(!useIndent) {
                    sb.append(", ");
                }
            }
            if(useIndent) {
                doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("default ");
            } else {
                sb.append(", default ");
            }
            try {
                sb.append(getDefault(device));
            } catch (GLException gle) {
                sb.append("n/a");
            }
        }
        if(useIndent) {
            sb.append(Platform.getNewline());
        } else {
            sb.append("]");
        }

        return sb;
    }
    
    /** Uses the default device */
    public static String glAvailabilityToString() {
        return glAvailabilityToString(null);
    }

    //
    // Public (user-visible) profiles
    //

    /** The desktop OpenGL compatibility profile 4.x, with x >= 0, ie GL2 plus GL4.<br>
        <code>bc</code> stands for backward compatibility. */
    public static final String GL4bc = "GL4bc";

    /** The desktop OpenGL core profile 4.x, with x >= 0 */
    public static final String GL4   = "GL4";

    /** The desktop OpenGL compatibility profile 3.x, with x >= 1, ie GL2 plus GL3.<br>
        <code>bc</code> stands for backward compatibility. */
    public static final String GL3bc = "GL3bc";

    /** The desktop OpenGL core profile 3.x, with x >= 1 */
    public static final String GL3   = "GL3";

    /** The desktop OpenGL profile 1.x up to 3.0 */
    public static final String GL2   = "GL2";

    /** The embedded OpenGL profile ES 1.x, with x >= 0 */
    public static final String GLES1 = "GLES1";

    /** The embedded OpenGL profile ES 2.x, with x >= 0 */
    public static final String GLES2 = "GLES2";

    /** The intersection of the desktop GL2 and embedded ES1 profile */
    public static final String GL2ES1 = "GL2ES1";

    /** The intersection of the desktop GL3, GL2 and embedded ES2 profile */
    public static final String GL2ES2 = "GL2ES2";

    /** The intersection of the desktop GL3 and GL2 profile */
    public static final String GL2GL3 = "GL2GL3";

    /** The default profile, used for the device default profile map  */
    private static final String GL_DEFAULT = "GL_DEFAULT";

    /** 
     * All GL Profiles in the order of default detection.
     * Desktop compatibility profiles (the one with fixed function pipeline) comes first
     * from highest to lowest version.
     * <p> This includes the generic subset profiles GL2GL3, GL2ES2 and GL2ES1.</p>
     *
     * <ul>
     *  <li> GL4bc
     *  <li> GL3bc
     *  <li> GL2
     *  <li> GL4
     *  <li> GL3
     *  <li> GL2GL3
     *  <li> GLES2
     *  <li> GL2ES2
     *  <li> GLES1
     *  <li> GL2ES1
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_ALL = new String[] { GL4bc, GL3bc, GL2, GL4, GL3, GL2GL3, GLES2, GL2ES2, GLES1, GL2ES1 };

    /**
     * Order of maximum profiles.
     *
     * <ul>
     *  <li> GL4bc
     *  <li> GL4
     *  <li> GL3bc
     *  <li> GL3
     *  <li> GL2
     *  <li> GLES2
     *  <li> GLES1
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_MAX = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GLES2, GLES1 };

    /**
     * Order of minimum profiles.
     *
     * <ul>
     *  <li> GLES1
     *  <li> GLES2
     *  <li> GL2
     *  <li> GL3
     *  <li> GL3bc
     *  <li> GL4
     *  <li> GL4bc
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_MIN = new String[] { GLES1, GLES2, GL2, GL3, GL3bc, GL4, GL4bc };
    
    /**
     * Order of minimum original desktop profiles.
     *
     * <ul>
     *  <li> GL2
     *  <li> GL3bc
     *  <li> GL4bc
     *  <li> GL3
     *  <li> GL4
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_MIN_DESKTOP = new String[] { GL2, GL3bc, GL4bc, GL3, GL4 };
    
    /**
     * Order of maximum fixed function profiles
     *
     * <ul>
     *  <li> GL4bc
     *  <li> GL3bc
     *  <li> GL2
     *  <li> GLES1
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_MAX_FIXEDFUNC = new String[] { GL4bc, GL3bc, GL2, GLES1 };

    /**
     * Order of maximum programmable shader profiles
     *
     * <ul>
     *  <li> GL4bc
     *  <li> GL4
     *  <li> GL3bc
     *  <li> GL3
     *  <li> GL2
     *  <li> GLES2
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GLES2 };

    /**
     * Order of maximum programmable shader <i>core only</i> profiles
     *
     * <ul>
     *  <li> GL4
     *  <li> GL3
     *  <li> GLES2
     * </ul>
     *
     */
    public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER_CORE = new String[] { GL4, GL3, GLES2 };
    
    /** Returns a default GLProfile object, reflecting the best for the running platform.
     * It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL}
     * and favors hardware acceleration.
     * @throws GLException if no profile is available for the device.
     * @see #GL_PROFILE_LIST_ALL
     */
    public static GLProfile getDefault(AbstractGraphicsDevice device) {
        GLProfile glp = get(device, GL_DEFAULT);
        return glp;
    }

    /** Returns a default GLProfile object, reflecting the best for the running platform.
     * It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL}
     * and favors hardware acceleration.
     * <p>Uses the default device.</p> 
     * @throws GLException if no profile is available for the default device.
     */
    public static GLProfile getDefault() {
        return getDefault(defaultDevice);
    }

    /**
     * Returns the highest profile.
     * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX}
     *
     * @throws GLException if no profile is available for the device.
     * @see #GL_PROFILE_LIST_MAX
     */
    public static GLProfile getMaximum(AbstractGraphicsDevice device, boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(device, GL_PROFILE_LIST_MAX, favorHardwareRasterizer);
    }

    /** Uses the default device 
     * @throws GLException if no profile is available for the default device.
     * @see #GL_PROFILE_LIST_MAX
     */
    public static GLProfile getMaximum(boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(GL_PROFILE_LIST_MAX, favorHardwareRasterizer);
    }

    /**
     * Returns the lowest profile.
     * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MIN}
     *
     * @throws GLException if no desktop profile is available for the device.
     * @see #GL_PROFILE_LIST_MIN
     */
    public static GLProfile getMinimum(AbstractGraphicsDevice device, boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(device, GL_PROFILE_LIST_MIN, favorHardwareRasterizer);
    }

    /** Uses the default device 
     * @throws GLException if no desktop profile is available for the default device.
     * @see #GL_PROFILE_LIST_MIN
     */
    public static GLProfile getMinimum(boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(GL_PROFILE_LIST_MIN, favorHardwareRasterizer);
    }


    /**
     * Returns the highest profile, implementing the fixed function pipeline.
     * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_FIXEDFUNC}
     *
     * @throws GLException if no fixed function profile is available for the device.
     * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC
     */
    public static GLProfile getMaxFixedFunc(AbstractGraphicsDevice device, boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(device, GL_PROFILE_LIST_MAX_FIXEDFUNC, favorHardwareRasterizer);
    }

    /** Uses the default device 
     * @throws GLException if no fixed function profile is available for the default device.
     * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC
     */
    public static GLProfile getMaxFixedFunc(boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(GL_PROFILE_LIST_MAX_FIXEDFUNC, favorHardwareRasterizer);
    }

    /**
     * Returns the highest profile, implementing the programmable shader pipeline.
     * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER}
     *
     * @throws GLException if no programmable profile is available for the device.
     * @see #GL_PROFILE_LIST_MAX_PROGSHADER
     */
    public static GLProfile getMaxProgrammable(AbstractGraphicsDevice device, boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(device, GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer);
    }

    /** Uses the default device 
     * @throws GLException if no programmable profile is available for the default device.
     * @see #GL_PROFILE_LIST_MAX_PROGSHADER
     */
    public static GLProfile getMaxProgrammable(boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer);
    }

    /**
     * Returns the highest profile, implementing the programmable shader <i>core</i> pipeline <i>only</i>.
     * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER_CORE}
     *
     * @throws GLException if no programmable core profile is available for the device.
     * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE
     */
    public static GLProfile getMaxProgrammableCore(AbstractGraphicsDevice device, boolean favorHardwareRasterizer)
        throws GLException
    {            
        return get(device, GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer);
    }

    /** Uses the default device 
     * @throws GLException if no programmable core profile is available for the default device.
     * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE
     */
    public static GLProfile getMaxProgrammableCore(boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer);
    }
    
    /** 
     * Returns the GL2ES1 profile implementation, hence compatible w/ GL2ES1.<br/>
     * It returns:
     * <pre>
     *   GLProfile.get(device, GLProfile.GL2ES1).getImpl());
     * </pre>
     * <p>Selection favors hardware rasterizer.</p>
     *
     * @throws GLException if no GL2ES1 compatible profile is available for the default device.
     * @see #isGL2ES1()
     * @see #get(AbstractGraphicsDevice, String)
     * @see #getImpl()
     */
    public static GLProfile getGL2ES1(AbstractGraphicsDevice device)
        throws GLException
    {
        return get(device, GL2ES1).getImpl();
    }

    /** 
     * Calls {@link #getGL2ES1(AbstractGraphicsDevice)} using the default device. 
     * <p>Selection favors hardware rasterizer.</p>
     * @see #getGL2ES1(AbstractGraphicsDevice)
     */
    public static GLProfile getGL2ES1()
        throws GLException
    {
        return get(defaultDevice, GL2ES1).getImpl();
    }

    /** 
     * Returns the GL2ES2 profile implementation, hence compatible w/ GL2ES2.<br/>
     * It returns:
     * <pre>
     *   GLProfile.get(device, GLProfile.GL2ES2).getImpl());
     * </pre>
     * <p>Selection favors hardware rasterizer.</p>
     *
     * @throws GLException if no GL2ES2 compatible profile is available for the default device.
     * @see #isGL2ES2()
     * @see #get(AbstractGraphicsDevice, String)
     * @see #getImpl()
     */
    public static GLProfile getGL2ES2(AbstractGraphicsDevice device)
        throws GLException
    {
        return get(device, GL2ES2).getImpl();
    }

    /** 
     * Calls {@link #getGL2ES2(AbstractGraphicsDevice)} using the default device. 
     * <p>Selection favors hardware rasterizer.</p>
     * @see #getGL2ES2(AbstractGraphicsDevice)
     */
    public static GLProfile getGL2ES2()
        throws GLException
    {
        return get(defaultDevice, GL2ES2).getImpl();
    }

    /** 
     * Returns the GL2GL3 profile implementation, hence compatible w/ GL2GL3.<br/>
     * It returns:
     * <pre>
     *   GLProfile.get(device, GLProfile.GL2GL3).getImpl());
     * </pre>
     * <p>Selection favors hardware rasterizer.</p>
     *
     * @throws GLException if no GL2GL3 compatible profile is available for the default device.
     * @see #isGL2GL3()
     * @see #get(AbstractGraphicsDevice, String)
     * @see #getImpl()
     */
    public static GLProfile getGL2GL3(AbstractGraphicsDevice device)
        throws GLException
    {
        return get(device, GL2GL3).getImpl();
    }

    /** 
     * Calls {@link #getGL2GL3(AbstractGraphicsDevice)} using the default device. 
     * <p>Selection favors hardware rasterizer.</p>
     * @see #getGL2GL3(AbstractGraphicsDevice)
     */
    public static GLProfile getGL2GL3()
        throws GLException
    {
        return get(defaultDevice, GL2GL3).getImpl();
    }

    /** Returns a GLProfile object.
     * verifies the given profile and chooses an appropriate implementation.
     * A generic value of <code>null</code> or <code>GL</code> will result in
     * the default profile.
     *
     * @param device a valid AbstractGraphicsDevice, or <code>null</null> for the default device.
     * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), 
     *        or <code>[ null, GL ]</code> for the default profile.
     * @throws GLException if the requested profile is not available for the device.
     */
    public static GLProfile get(AbstractGraphicsDevice device, String profile)
        throws GLException
    {
        if(null==profile || profile.equals("GL")) {
            profile = GL_DEFAULT;
        }
        final HashMap<String /*GLProfile_name*/, GLProfile> glpMap = getProfileMap(device, true);
        final GLProfile glp = glpMap.get(profile);
        if(null == glp) {
            throw new GLException("Profile "+profile+" is not available on "+device+", but: "+glpMap.values());
        }
        return glp;
    }

    /** Uses the default device 
     * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), 
     *        or <code>[ null, GL ]</code> for the default profile.
     * @throws GLException if the requested profile is not available for the default device.
     */
    public static GLProfile get(String profile)
        throws GLException
    {
        return get(defaultDevice, profile);
    }

    /**
     * Returns the first profile from the given list,
     * where an implementation is available.
     *
     * @param device a valid AbstractGraphicsDevice, or <code>null</null> for the default device.
     * @param profiles array of valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..)
     * @param favorHardwareRasterizer set to true, if hardware rasterizer shall be favored, otherwise false. 
     * @throws GLException if the non of the requested profiles is available for the device.
     */
    public static GLProfile get(AbstractGraphicsDevice device, String[] profiles, boolean favorHardwareRasterizer)
        throws GLException
    {
        GLProfile glProfileAny = null;
        
        HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device, true);
        for(int i=0; i<profiles.length; i++) {
            final GLProfile glProfile = map.get(profiles[i]);
            if(null!=glProfile) {
                if(!favorHardwareRasterizer) {
                    return glProfile;
                }
                if(glProfile.isHardwareRasterizer()) {
                    return glProfile;
                }
                if(null==glProfileAny) {
                    glProfileAny = glProfile;
                }                
            }
        }
        if(null!=glProfileAny) {
            return glProfileAny;
        }                
        throw new GLException("Profiles "+array2String(profiles)+" not available on device "+device);
    }

    /** Uses the default device 
     * @param profiles array of valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..) 
     * @param favorHardwareRasterizer set to true, if hardware rasterizer shall be favored, otherwise false. 
     * @throws GLException if the non of the requested profiles is available for the default device.
     */
    public static GLProfile get(String[] profiles, boolean favorHardwareRasterizer)
        throws GLException
    {
        return get(defaultDevice, profiles, favorHardwareRasterizer);
    }
    
    /** Indicates whether the native OpenGL ES1 profile is in use. 
     * This requires an EGL interface.
     */
    public static boolean usesNativeGLES1(String profileImpl) {
        return GLES1.equals(profileImpl);
    }

    /** Indicates whether the native OpenGL ES2 profile is in use. 
     * This requires an EGL or ES2 compatible interface.
     */
    public static boolean usesNativeGLES2(String profileImpl) {
        return GLES2.equals(profileImpl);
    }

    /** Indicates whether either of the native OpenGL ES profiles are in use. */
    public static boolean usesNativeGLES(String profileImpl) {
        return usesNativeGLES2(profileImpl) || usesNativeGLES1(profileImpl);
    }

    /** @return {@link javax.media.nativewindow.NativeWindowFactory#isAWTAvailable()} and
        JOGL's AWT part */
    public static boolean isAWTAvailable() { return isAWTAvailable; }

    public static String getGLTypeName(int type) {
        switch (type) {
        case GL.GL_UNSIGNED_BYTE:
            return "GL_UNSIGNED_BYTE";
        case GL.GL_BYTE:
            return "GL_BYTE";
        case GL.GL_UNSIGNED_SHORT:
            return "GL_UNSIGNED_SHORT";
        case GL.GL_SHORT:
            return "GL_SHORT";
        case GL.GL_FLOAT:
            return "GL_FLOAT";
        case GL.GL_FIXED:
            return "GL_FIXED";
        case javax.media.opengl.GL2ES2.GL_INT:
            return "GL_INT";
        case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
            return "GL_UNSIGNED_INT";
        case javax.media.opengl.GL2.GL_DOUBLE:
            return "GL_DOUBLE";
        case javax.media.opengl.GL2.GL_2_BYTES:
            return "GL_2_BYTES";
        case javax.media.opengl.GL2.GL_3_BYTES:
            return "GL_3_BYTES";
        case javax.media.opengl.GL2.GL_4_BYTES:
            return "GL_4_BYTES";
        }
        return null;
    }

    public static String getGLArrayName(int array) {
        switch(array) {
        case GLPointerFunc.GL_VERTEX_ARRAY:
            return "GL_VERTEX_ARRAY";
        case GLPointerFunc.GL_NORMAL_ARRAY:
            return "GL_NORMAL_ARRAY";
        case GLPointerFunc.GL_COLOR_ARRAY:
            return "GL_COLOR_ARRAY";
        case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
            return "GL_TEXTURE_COORD_ARRAY";
        }
        return null;
    }

    public final String getGLImplBaseClassName() {
        return getGLImplBaseClassName(getImplName());
    }

    private static final String getGLImplBaseClassName(String profileImpl) {
        if( GLES2 == profileImpl ) {
            return "jogamp.opengl.es2.GLES2";
        } else if( GLES1 == profileImpl ) {
            return "jogamp.opengl.es1.GLES1";
        } else if ( GL4bc == profileImpl ||
                    GL4   == profileImpl ||
                    GL3bc == profileImpl ||
                    GL3   == profileImpl ||
                    GL2   == profileImpl ) {
            return "jogamp.opengl.gl4.GL4bc";
        } else {
            throw new GLException("unsupported profile \"" + profileImpl + "\"");
        }
    }
    
    /**
     * @param o GLProfile object to compare with
     * @return true if given Object is a GLProfile and
     *         if both, profile and profileImpl is equal with this.
     */
    public final boolean equals(Object o) {
        if(this==o) { return true; }
        if(o instanceof GLProfile) {
            final GLProfile glp = (GLProfile)o;
            return getName() == glp.getName() && getImplName() == glp.getImplName() ;
        }
        return false;
    }

    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + getImplName().hashCode();
        hash = 97 * hash + getName().hashCode();
        return hash;
    }
 
    /**
     * @param glp GLProfile to compare with
     * @throws GLException if given GLProfile and this aren't equal
     */
    public final void verifyEquality(GLProfile glp) throws GLException  {
        if(!this.equals(glp)) {
            throw new GLException("GLProfiles are not equal: "+this+" != "+glp);
        }
    }

    /** return this profiles name */
    public final String getName() {
        return profile;
    }

    /** return this profiles implementation, eg. GL2ES2 -> GL2, or GL3 -> GL3 */
    public final GLProfile getImpl() {
        return null != profileImpl ? profileImpl : this;
    }
    
    /** return true if impl. is a hardware rasterizer, otherwise false. */
    public final boolean isHardwareRasterizer() {
        return isHardwareRasterizer;
    }
    
    /** 
     * return this profiles implementation name, eg. GL2ES2 -> GL2, or GL3 -> GL3 
     */
    public final String getImplName() {
        return null != profileImpl ? profileImpl.getName() : getName();
    }

    /** Indicates whether this profile is capable of GL4bc.  <p>Includes [ GL4bc ].</p> */
    public final boolean isGL4bc() {
        return GL4bc == profile;
    }

    /** Indicates whether this profile is capable of GL4.    <p>Includes [ GL4bc, GL4 ].</p> */
    public final boolean isGL4() {
        return isGL4bc() || GL4 == profile;
    }

    /** Indicates whether this profile is capable of GL3bc.  <p>Includes [ GL4bc, GL3bc ].</p> */
    public final boolean isGL3bc() {
        return isGL4bc() || GL3bc == profile;
    }

    /** Indicates whether this profile is capable of GL3.    <p>Includes [ GL4bc, GL4, GL3bc, GL3 ].</p> */
    public final boolean isGL3() {
        return isGL4() || isGL3bc() || GL3 == profile;
    }

    /** Indicates whether this context is a GL2 context      <p>Includes [ GL4bc, GL3bc, GL2 ].</p> */
    public final boolean isGL2() {
        return isGL3bc() || GL2 == profile;
    }

    /** Indicates whether this profile is capable of GLES1.  <p>Includes [ GLES1 ].</p> */
    public final boolean isGLES1() {
        return GLES1 == profile;
    }

    /** Indicates whether this profile is capable of GLES2.  <p>Includes [ GLES2 ].</p> */
    public final boolean isGLES2() {
        return GLES2 == profile;
    }
    
    /** Indicates whether this profile is capable of GLES.  <p>Includes [ GLES1, GLES2 ].</p> */
    public final boolean isGLES() {
        return GLES2 == profile || GLES1 == profile;
    }

    /** Indicates whether this profile is capable of GL2ES1. <p>Includes [ GL4bc, GL3bc, GL2, GLES1, GL2ES1 ].</p> */
    public final boolean isGL2ES1() {
        return GL2ES1 == profile || isGLES1() || isGL2();
    }

    /** Indicates whether this profile is capable os GL2GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3 ].</p> */
    public final boolean isGL2GL3() {
        return GL2GL3 == profile || isGL3() || isGL2();
    }

    /** Indicates whether this profile is capable os GL2ES2. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3, GL2ES2, GLES2 ].</p> */
    public final boolean isGL2ES2() {
        return GL2ES2 == profile || isGLES2() || isGL2GL3();
    }

    /** Indicates whether this profile supports GLSL, ie. {@link #isGL2ES2()}. */
    public final boolean hasGLSL() {
        return isGL2ES2() ;
    }

    /** Indicates whether this profile uses the native OpenGL ES1 implementations. */
    public final boolean usesNativeGLES1() {
        return GLES1 == getImplName();
    }

    /** Indicates whether this profile uses the native OpenGL ES2 implementations. */
    public final boolean usesNativeGLES2() {
        return GLES2 == getImplName();
    }

    /** Indicates whether this profile uses either of the native OpenGL ES implementations. */
    public final boolean usesNativeGLES() {
        return usesNativeGLES2() || usesNativeGLES1();
    }

    /** 
     * General validation if type is a valid GL data type
     * for the current profile
     */
    public boolean isValidDataType(int type, boolean throwException) {
        switch(type) {
            case GL.GL_UNSIGNED_BYTE:
            case GL.GL_BYTE:
            case GL.GL_UNSIGNED_SHORT:
            case GL.GL_SHORT:
            case GL.GL_FLOAT:
            case GL.GL_FIXED:
                return true;
            case javax.media.opengl.GL2ES2.GL_INT:
            case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
                if( isGL2ES2() ) {
                    return true;
                }
            case javax.media.opengl.GL2.GL_DOUBLE:
                if( isGL3() ) {
                    return true;
                }
            case javax.media.opengl.GL2.GL_2_BYTES:
            case javax.media.opengl.GL2.GL_3_BYTES:
            case javax.media.opengl.GL2.GL_4_BYTES:
                if( isGL2() ) {
                    return true;
                }
        } 
        if(throwException) {
            throw new GLException("Illegal data type on profile "+this+": "+type);
        }
        return false;
    }
    
    public boolean isValidArrayDataType(int index, int comps, int type, 
                                        boolean isVertexAttribPointer, boolean throwException) {
        String arrayName = getGLArrayName(index);
        if(isGLES1()) {
            if(isVertexAttribPointer) {
                if(throwException) {
                    throw new GLException("Illegal array type for "+arrayName+" on profile GLES1: VertexAttribPointer");
                }
                return false;
            }
            switch(index) {
                case GLPointerFunc.GL_VERTEX_ARRAY:
                case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
                    switch(type) {
                        case GL.GL_BYTE:
                        case GL.GL_SHORT:
                        case GL.GL_FIXED:
                        case GL.GL_FLOAT:
                            break;
                        default: 
                            if(throwException) {
                                throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
                            }
                            return false;
                    }
                    switch(comps) {
                        case 0:
                        case 2:
                        case 3:
                        case 4:
                            break;
                        default: 
                            if(throwException) {
                                throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
                            }
                            return false;
                    }
                    break;
                case GLPointerFunc.GL_NORMAL_ARRAY:
                    switch(type) {
                        case GL.GL_BYTE:
                        case GL.GL_SHORT:
                        case GL.GL_FIXED:
                        case GL.GL_FLOAT:
                            break;
                        default: 
                            if(throwException) {
                                throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
                            }
                            return false;
                    }
                    switch(comps) {
                        case 0:
                        case 3:
                            break;
                        default: 
                            if(throwException) {
                                throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
                            }
                            return false;
                    }
                    break;
                case GLPointerFunc.GL_COLOR_ARRAY:
                    switch(type) {
                        case GL.GL_UNSIGNED_BYTE:
                        case GL.GL_FIXED:
                        case GL.GL_FLOAT:
                            break;
                        default: 
                            if(throwException) {
                                throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
                            }
                            return false;
                    }
                    switch(comps) {
                        case 0:
                        case 4:
                            break;
                        default: 
                            if(throwException) {
                                throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
                            }
                            return false;
                    }
                    break;
            }
        } else if(isGLES2()) {
            // simply ignore !isVertexAttribPointer case, since it is simulated anyway ..
            switch(type) {
                case GL.GL_UNSIGNED_BYTE:
                case GL.GL_BYTE:
                case GL.GL_UNSIGNED_SHORT:
                case GL.GL_SHORT:
                case GL.GL_FLOAT:
                case GL.GL_FIXED:
                    break;
                default: 
                    if(throwException) {
                        throw new GLException("Illegal data type for "+arrayName+" on profile GLES2: "+type);
                    }
                    return false;
            }
            /** unable to validate .. could be any valid type/component combination
            switch(comps) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                    break;
                default: 
                    if(throwException) {
                        throw new GLException("Illegal component number for "+arrayName+" on profile GLES2: "+comps);
                    }
                    return false;
            } */
        } else if( isGL2ES2() ) {
            if(isVertexAttribPointer) {
                switch(type) {
                    case GL.GL_UNSIGNED_BYTE:
                    case GL.GL_BYTE:
                    case GL.GL_UNSIGNED_SHORT:
                    case GL.GL_SHORT:
                    case GL.GL_FLOAT:
                    case javax.media.opengl.GL2ES2.GL_INT:
                    case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
                    case javax.media.opengl.GL2.GL_DOUBLE:
                        break;
                    default: 
                        if(throwException) {
                            throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
                        }
                        return false;
                }
                switch(comps) {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                        break;
                    default: 
                        if(throwException) {
                            throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
                        }
                        return false;
                }
            } else {
                switch(index) {
                    case GLPointerFunc.GL_VERTEX_ARRAY:
                        switch(type) {
                            case GL.GL_SHORT:
                            case GL.GL_FLOAT:
                            case javax.media.opengl.GL2ES2.GL_INT:
                            case javax.media.opengl.GL2.GL_DOUBLE:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
                                }
                                return false;
                        }
                        switch(comps) {
                            case 0:
                            case 2:
                            case 3:
                            case 4:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
                                }
                                return false;
                        }
                        break;
                    case GLPointerFunc.GL_NORMAL_ARRAY:
                        switch(type) {
                            case GL.GL_BYTE:
                            case GL.GL_SHORT:
                            case GL.GL_FLOAT:
                            case javax.media.opengl.GL2ES2.GL_INT:
                            case javax.media.opengl.GL2.GL_DOUBLE:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
                                }
                                return false;
                        }
                        switch(comps) {
                            case 0:
                            case 3:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
                                }
                                return false;
                        }
                        break;
                    case GLPointerFunc.GL_COLOR_ARRAY:
                        switch(type) {
                            case GL.GL_UNSIGNED_BYTE:
                            case GL.GL_BYTE:
                            case GL.GL_UNSIGNED_SHORT:
                            case GL.GL_SHORT:
                            case GL.GL_FLOAT:
                            case javax.media.opengl.GL2ES2.GL_INT:
                            case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
                            case javax.media.opengl.GL2.GL_DOUBLE:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
                                }
                                return false;
                        }
                        switch(comps) {
                            case 0:
                            case 3:
                            case 4:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
                                }
                                return false;
                        }
                        break;
                    case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
                        switch(type) {
                            case GL.GL_SHORT:
                            case GL.GL_FLOAT:
                            case javax.media.opengl.GL2ES2.GL_INT:
                            case javax.media.opengl.GL2.GL_DOUBLE:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
                                }
                                return false;
                        }
                        switch(comps) {
                            case 0:
                            case 1:
                            case 2:
                            case 3:
                            case 4:
                                break;
                            default: 
                                if(throwException) {
                                    throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
                                }
                                return false;
                        }
                        break;
                }
            }
        }
        return true;
    }

    public String toString() {
        return "GLProfile[" + getName() + "/" + getImplName() + "."+(this.isHardwareRasterizer?"hw":"sw")+"]";
    }

    private static /*final*/ boolean isAWTAvailable;

    private static /*final*/ boolean hasDesktopGLFactory;    
    private static /*final*/ boolean hasGL234Impl;
    private static /*final*/ boolean hasEGLFactory;
    private static /*final*/ boolean hasGLES2Impl;
    private static /*final*/ boolean hasGLES1Impl;

    private static /*final*/ GLDrawableFactoryImpl eglFactory = null;
    private static /*final*/ GLDrawableFactoryImpl desktopFactory = null;
    private static /*final*/ AbstractGraphicsDevice defaultDevice = null;

    private static volatile boolean initialized = false;
    private static RecursiveThreadGroupLock initLock = LockFactory.createRecursiveThreadGroupLock();

    /**
     * Tries the profiles implementation and native libraries.
     */
    private static void initProfilesForDefaultDevices() {
        NativeWindowFactory.initSingleton();
        if(DEBUG) {
            System.err.println("GLProfile.init - thread: " + Thread.currentThread().getName());
            System.err.println(VersionUtil.getPlatformInfo());
            System.err.println(GlueGenVersion.getInstance());
            System.err.println(NativeWindowVersion.getInstance());
            System.err.println(JoglVersion.getInstance());
        }

        ClassLoader classloader = GLProfile.class.getClassLoader();

        isAWTAvailable = NativeWindowFactory.isAWTAvailable() &&
                         ReflectionUtil.isClassAvailable("javax.media.opengl.awt.GLCanvas", classloader) ; // JOGL

        // depends on hasDesktopGLFactory
        hasGL234Impl   = ReflectionUtil.isClassAvailable("jogamp.opengl.gl4.GL4bcImpl", classloader);
        
        // depends on hasEGLFactory
        hasGLES1Impl   = ReflectionUtil.isClassAvailable("jogamp.opengl.es1.GLES1Impl", classloader);
        hasGLES2Impl   = ReflectionUtil.isClassAvailable("jogamp.opengl.es2.GLES2Impl", classloader);
        
        //
        // Iteration of desktop GL availability detection
        // utilizing the detected GL version in the shared context.
        //
        // - Instantiate GLDrawableFactory incl its shared dummy drawable/context,
        //   which will register at GLContext ..
        //
        GLDrawableFactory.initSingleton();
        
        Throwable t=null;
        // if successfull it has a shared dummy drawable and context created
        try {
            desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2);
            if(null != desktopFactory) {
                DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(0);
                if(null!=glLookupHelper) {
                    hasDesktopGLFactory = glLookupHelper.isLibComplete() && hasGL234Impl;
                }
            }
        } catch (LinkageError le) {
            t=le;
        } catch (RuntimeException re) {
            t=re;
        } catch (Throwable tt) {
            t=tt;
        }
        if(DEBUG) {
            if(null!=t) {
                t.printStackTrace();
            }
        }

        final AbstractGraphicsDevice defaultDesktopDevice;
        if(null == desktopFactory) {
            hasDesktopGLFactory  = false;
            hasGL234Impl         = false;
            defaultDesktopDevice = null;
            if(DEBUG) {
                System.err.println("Info: GLProfile.init - Desktop GLDrawable factory not available");
            }
        } else {
            defaultDesktopDevice = desktopFactory.getDefaultDevice();
        }

        if ( ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) {
            t=null;
            try {
                eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2);
                if(null != eglFactory) {
                    hasEGLFactory = true;
                    // update hasGLES1Impl, hasGLES2Impl based on EGL
                    hasGLES2Impl = null!=eglFactory.getGLDynamicLookupHelper(2) && hasGLES2Impl;
                    hasGLES1Impl = null!=eglFactory.getGLDynamicLookupHelper(1) && hasGLES1Impl;
                }
            } catch (LinkageError le) {
                t=le;
            } catch (SecurityException se) {
                t=se;
            } catch (NullPointerException npe) {
                t=npe;
            } catch (RuntimeException re) {
                t=re;
            }
            if(DEBUG) {
                if(null!=t) {
                    t.printStackTrace();
                }
            }
        }

        final AbstractGraphicsDevice defaultEGLDevice;
        if(null == eglFactory) {
            hasGLES2Impl     = false;
            hasGLES1Impl     = false;
            defaultEGLDevice = null;
            if(DEBUG) {
                System.err.println("Info: GLProfile.init - EGL GLDrawable factory not available");
            }
        } else {
            defaultEGLDevice = eglFactory.getDefaultDevice();            
        }

        if( null != defaultDesktopDevice ) {
            defaultDevice = defaultDesktopDevice;
            if(DEBUG) {
                System.err.println("Info: GLProfile.init - Default device is desktop derived: "+defaultDevice);
            }            
        } else if ( null != defaultEGLDevice ) {
            defaultDevice = defaultEGLDevice;
            if(DEBUG) {
                System.err.println("Info: GLProfile.init - Default device is EGL derived: "+defaultDevice);
            }
        } else {
            if(DEBUG) {
                System.err.println("Info: GLProfile.init - Default device not available");
            }
            defaultDevice = null;
        }
                
        // we require to initialize the EGL device 1st, if available
        final boolean addedEGLProfile     = null != defaultEGLDevice     ? initProfilesForDevice(defaultEGLDevice)     : false;
        final boolean addedDesktopProfile = null != defaultDesktopDevice ? initProfilesForDevice(defaultDesktopDevice) : false;        
        final boolean addedAnyProfile     = addedEGLProfile || addedDesktopProfile ;
    
        if(DEBUG) {
            System.err.println("GLProfile.init addedAnyProfile       "+addedAnyProfile+" (desktop: "+addedDesktopProfile+", egl "+addedEGLProfile+")");
            System.err.println("GLProfile.init isAWTAvailable        "+isAWTAvailable);
            System.err.println("GLProfile.init hasDesktopGLFactory   "+hasDesktopGLFactory);
            System.err.println("GLProfile.init hasGL234Impl          "+hasGL234Impl);
            System.err.println("GLProfile.init hasEGLFactory         "+hasEGLFactory);
            System.err.println("GLProfile.init hasGLES1Impl          "+hasGLES1Impl);
            System.err.println("GLProfile.init hasGLES2Impl          "+hasGLES2Impl);
            System.err.println("GLProfile.init defaultDevice         "+defaultDevice);
            System.err.println("GLProfile.init defaultDevice Desktop "+defaultDesktopDevice);
            System.err.println("GLProfile.init defaultDevice EGL     "+defaultEGLDevice);
            System.err.println("GLProfile.init profile order         "+array2String(GL_PROFILE_LIST_ALL));
        }
    }

    /**
     * @param device the device for which profiles shall be initialized
     * @return true if any profile for the device exists, otherwise false
     */
    private static boolean initProfilesForDevice(AbstractGraphicsDevice device) {
        if(null == device) {
            return false;
        }
        initLock.lock();
        try {
            GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device);
            factory.enterThreadCriticalZone();
            try {
                return initProfilesForDeviceCritical(device);
            } finally {
                factory.leaveThreadCriticalZone();
            }
        } finally {
            initLock.unlock();
        }
    }
    private static boolean initProfilesForDeviceCritical(AbstractGraphicsDevice device) {
        boolean isSet = GLContext.getAvailableGLVersionsSet(device);

        if(DEBUG) {
            System.err.println("Info: GLProfile.initProfilesForDevice: "+device+" ("+device.getClass().getName()+"), isSet "+isSet+", hasDesktopGLFactory "+hasDesktopGLFactory+", hasEGLFactory "+hasEGLFactory);
        }
        if(isSet) {
            // Avoid recursion and check whether impl. is sane!
            final String deviceKey = device.getUniqueID();
            HashMap<String /*GLProfile_name*/, GLProfile> map = deviceConn2ProfileMap.get(deviceKey);
            if( null == map ) {
                throw new InternalError("GLContext Avail. GLVersion is set - but no profile map for device: "+device);
            }
            return null != map.get(GL_DEFAULT);
        }

        boolean addedDesktopProfile = false;
        boolean addedEGLProfile = false;

        final boolean deviceIsDesktopCompatible = hasDesktopGLFactory && desktopFactory.getIsDeviceCompatible(device);        
                
        if( deviceIsDesktopCompatible ) {
            // 1st pretend we have all Desktop and EGL profiles ..
            computeProfileMap(device, true /* desktopCtxUndef*/, true  /* esCtxUndef */);

            // Triggers eager initialization of share context in GLDrawableFactory for the device,
            // hence querying all available GLProfiles
            final Thread sharedResourceThread = desktopFactory.getSharedResourceThread();
            if(null != sharedResourceThread) {
                initLock.addOwner(sharedResourceThread);
            }
            boolean desktopSharedCtxAvail = desktopFactory.createSharedResource(device);
            if(null != sharedResourceThread) {
                initLock.removeOwner(sharedResourceThread);
            }
            if (DEBUG) {
                System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail);
            }
            if(!desktopSharedCtxAvail) {
                hasDesktopGLFactory = false;
            } else if( !GLContext.getAvailableGLVersionsSet(device) ) {
                throw new InternalError("Available GLVersions not set");
            }
            addedDesktopProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */);
        }
        
        final boolean deviceIsEGLCompatible = hasEGLFactory && eglFactory.getIsDeviceCompatible(device);
        
        // also test GLES1 and GLES2 on desktop, since we have implementations / emulations available.
        if( deviceIsEGLCompatible && ( hasGLES2Impl || hasGLES1Impl ) ) {
            // 1st pretend we have all EGL profiles ..
            computeProfileMap(device, false /* desktopCtxUndef*/, true /* esCtxUndef */);

            // Triggers eager initialization of share context in GLDrawableFactory for the device,
            // hence querying all available GLProfiles
            final Thread sharedResourceThread = eglFactory.getSharedResourceThread();
            if(null != sharedResourceThread) {
                initLock.addOwner(sharedResourceThread);
            }
            boolean eglSharedCtxAvail = eglFactory.createSharedResource(device);
            if(null != sharedResourceThread) {
                initLock.removeOwner(sharedResourceThread);
            }
            if(!eglSharedCtxAvail) {
                // Remark: On Windows there is a libEGL.dll delivered w/ Chrome 15.0.874.121m and Firefox 8.0.1
                // but it seems even EGL.eglInitialize(eglDisplay, null, null) 
                // fails in some scenarios (eg VirtualBox 4.1.6) w/ EGL error 0x3001 (EGL_NOT_INITIALIZED).
                hasEGLFactory = false;
                hasGLES2Impl = false;
                hasGLES1Impl = false;
            }
            if (DEBUG) {
                System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail);
            }
            addedEGLProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */);
        }

        if( !addedDesktopProfile && !addedEGLProfile ) {
            setProfileMap(device, new HashMap<String /*GLProfile_name*/, GLProfile>()); // empty
            if(DEBUG) {
                System.err.println("GLProfile: device could not be initialized: "+device);
                System.err.println("GLProfile: compatible w/ desktop: "+deviceIsDesktopCompatible+
                                            ", egl "+deviceIsEGLCompatible);
                System.err.println("GLProfile: desktoplFactory      "+desktopFactory);
                System.err.println("GLProfile: eglFactory           "+eglFactory);
                System.err.println("GLProfile: hasGLES1Impl         "+hasGLES1Impl);
                System.err.println("GLProfile: hasGLES2Impl         "+hasGLES2Impl);
            }
        }

        if(!GLContext.getAvailableGLVersionsSet(device)) {
            GLContext.setAvailableGLVersionsSet(device);
        }

        if (DEBUG) {
            System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": added profile(s): desktop "+addedDesktopProfile+", egl "+addedEGLProfile);
            System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": "+glAvailabilityToString(device));
            if(addedDesktopProfile) {
                dumpGLInfo(desktopFactory, device);
                List<GLCapabilitiesImmutable> availCaps = desktopFactory.getAvailableCapabilities(device);
                for(int i=0; i<availCaps.size(); i++) {
                    System.err.println(availCaps.get(i));
                }
            } else if(addedEGLProfile) {
                dumpGLInfo(eglFactory, device);
                List<GLCapabilitiesImmutable> availCaps = eglFactory.getAvailableCapabilities(device);
                for(int i=0; i<availCaps.size(); i++) {
                    System.err.println(availCaps.get(i));
                }
            }
        }

        return addedDesktopProfile || addedEGLProfile;
    }

    private static void dumpGLInfo(GLDrawableFactoryImpl factory, AbstractGraphicsDevice device)  {
        GLContext ctx = factory.getOrCreateSharedContext(device);
        if(null != ctx) {
            System.err.println("GLProfile.dumpGLInfo: "+ctx);
            ctx.makeCurrent();
            try {
                System.err.println(JoglVersion.getGLInfo(ctx.getGL(), null));
            } finally {
                ctx.release();
            }
        } else {
            System.err.println("GLProfile.dumpGLInfo: shared context n/a");
        }
    }

    public static AbstractGraphicsDevice getDefaultDevice() {
        initSingleton();
        return defaultDevice;
    }

    private static String array2String(String[] list) {
        StringBuilder msg = new StringBuilder();
        msg.append("[");
        for (int i = 0; i < list.length; i++) {
            if (i > 0)
                msg.append(", ");
            msg.append(list[i]);
        }
        msg.append("]");
        return msg.toString();
    }

    private static void glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb, int major, int profile) {
        String str = GLContext.getAvailableGLVersionAsString(device, major, profile);
        if(null==str) {
            throw new GLException("Internal Error");
        }
        sb.append("[");
        sb.append(str);
        sb.append("]");
    }

    private static boolean computeProfileMap(AbstractGraphicsDevice device, boolean desktopCtxUndef, boolean esCtxUndef) {
        if (DEBUG) {
            System.err.println("GLProfile.init map "+device.getConnection()+", desktopCtxUndef "+desktopCtxUndef+", esCtxUndef "+esCtxUndef);
        }
        final boolean isHardwareRasterizer[] = new boolean[1];
        GLProfile defaultGLProfileAny = null;
        GLProfile defaultGLProfileHW = null;
        HashMap<String, GLProfile> _mappedProfiles = new HashMap<String, GLProfile>(GL_PROFILE_LIST_ALL.length + 1 /* default */);
        for(int i=0; i<GL_PROFILE_LIST_ALL.length; i++) {
            String profile = GL_PROFILE_LIST_ALL[i];
            String profileImpl = computeProfileImpl(device, profile, desktopCtxUndef, esCtxUndef, isHardwareRasterizer);
            if(null!=profileImpl) {
                final GLProfile glProfile;
                if(profile.equals(profileImpl)) {
                    glProfile = new GLProfile(profile, null, isHardwareRasterizer[0]);
                } else {
                    final GLProfile _mglp = _mappedProfiles.get(profileImpl);
                    if(null == _mglp) {
                        throw new InternalError("XXX0");
                    }
                    glProfile = new GLProfile(profile, _mglp, isHardwareRasterizer[0]);
                }
                _mappedProfiles.put(profile, glProfile);
                if (DEBUG) {
                    System.err.println("GLProfile.init map "+glProfile+" on device "+device.getConnection());
                }
                if(null==defaultGLProfileHW && isHardwareRasterizer[0]) {
                    defaultGLProfileHW=glProfile;
                    if (DEBUG) {
                        System.err.println("GLProfile.init map defaultHW "+glProfile+" on device "+device.getConnection());
                    }
                } else if(null==defaultGLProfileAny) {
                    defaultGLProfileAny=glProfile;
                    if (DEBUG) {
                        System.err.println("GLProfile.init map defaultAny "+glProfile+" on device "+device.getConnection());
                    }
                }
            } else {
                if (DEBUG) {
                    System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getConnection());
                }
            }
        }
        if(null!=defaultGLProfileHW) {
            _mappedProfiles.put(GL_DEFAULT, defaultGLProfileHW);
        } else if(null!=defaultGLProfileAny) {
            _mappedProfiles.put(GL_DEFAULT, defaultGLProfileAny);
        }
        setProfileMap(device, _mappedProfiles);
        return _mappedProfiles.size() > 0;
    }

    /**
     * Returns the profile implementation
     */
    private static String computeProfileImpl(AbstractGraphicsDevice device, String profile, boolean desktopCtxUndef, boolean esCtxUndef, boolean isHardwareRasterizer[]) {
        // OSX GL3.. doesn't support GLSL<150, 
        // hence GL2ES2 and GL2GL3 need to be mapped on GL2 on OSX for GLSL compatibility.
        final boolean isOSX = Platform.OS_TYPE == Platform.OSType.MACOS;
        
        if (GL2ES1.equals(profile)) {
            final boolean es1HardwareRasterizer[] = new boolean[1];
            final boolean gles1Available = hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, es1HardwareRasterizer) );
            final boolean gles1HWAvailable = gles1Available && es1HardwareRasterizer[0] ;
            if(hasGL234Impl) {
                if(GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
                    if(!gles1HWAvailable || isHardwareRasterizer[0]) {
                        return GL4bc;
                    }
                }
                if(GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
                    if(!gles1HWAvailable || isHardwareRasterizer[0]) {
                        return GL3bc;
                    }
                }
                if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) {
                    if(!gles1HWAvailable || isHardwareRasterizer[0]) {
                        return GL2;
                    }
                }
            }
            if(gles1Available) {
                isHardwareRasterizer[0] = es1HardwareRasterizer[0];
                return GLES1;
            }
        } else if (GL2ES2.equals(profile)) {
            final boolean es2HardwareRasterizer[] = new boolean[1];
            final boolean gles2Available = hasGLES2Impl && ( esCtxUndef || GLContext.isGLES2Available(device, es2HardwareRasterizer) );
            final boolean gles2HWAvailable = gles2Available && es2HardwareRasterizer[0] ;
            if(hasGL234Impl) {
                if(!isOSX) {
                    if(GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
                        if(!gles2HWAvailable || isHardwareRasterizer[0]) {
                            return GL4bc;
                        }
                    }
                    if(GLContext.isGL4Available(device, isHardwareRasterizer)) {
                        if(!gles2HWAvailable || isHardwareRasterizer[0]) {
                            return GL4;
                        }
                    }
                    if(GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
                        if(!gles2HWAvailable || isHardwareRasterizer[0]) {
                            return GL3bc;
                        }
                    }
                    if(GLContext.isGL3Available(device, isHardwareRasterizer)) {
                        if(!gles2HWAvailable || isHardwareRasterizer[0]) {
                            return GL3;
                        }
                    }
                }
                if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) {
                    if(!gles2HWAvailable || isHardwareRasterizer[0]) {
                        return GL2;
                    }
                }
            }
            if(gles2Available) {
                isHardwareRasterizer[0] = es2HardwareRasterizer[0];
                return GLES2;
            }
        } else if(GL2GL3.equals(profile)) {
            if(hasGL234Impl) {
                if(!isOSX && GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
                    return GL4bc;
                } else if(!isOSX && GLContext.isGL4Available(device, isHardwareRasterizer)) {
                    return GL4;
                } else if(!isOSX && GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
                    return GL3bc;
                } else if(!isOSX && GLContext.isGL3Available(device, isHardwareRasterizer)) {
                    return GL3;
                } else if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) {
                    return GL2;
                }
            }
        } else if(GL4bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) {
            return GL4bc;
        } else if(GL4.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) {
            return GL4;
        } else if(GL3bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) {
            return GL3bc;
        } else if(GL3.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) {
            return GL3;
        } else if(GL2.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) {
            return GL2;
        } else if(GLES2.equals(profile) && hasGLES2Impl && ( esCtxUndef || GLContext.isGLES2Available(device, isHardwareRasterizer))) {
            return GLES2;
        } else if(GLES1.equals(profile) && hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, isHardwareRasterizer))) {
            return GLES1;
        }
        return null;
    }

    private static /*final*/ HashMap<String /*device_connection*/, HashMap<String /*GLProfile_name*/, GLProfile>> deviceConn2ProfileMap = 
                new HashMap<String /*device_connection*/, HashMap<String /*GLProfile_name*/, GLProfile>>();

    /**
     * This implementation support lazy initialization, while avoiding recursion/deadlocks.<br>
     * If no mapping 'device -> GLProfiles-Map' exists yet, it triggers<br>
     *  - create empty mapping device -> GLProfiles-Map <br>
     *  - initialization<br<
     *
     * @param device the key 'device -> GLProfiles-Map'
     * @param throwExceptionOnZeroProfile true if <code>GLException</code> shall be thrown in case of no mapped profile, otherwise false.
     * @return the GLProfile HashMap if exists, otherwise null 
     * @throws GLException if no profile for the given device is available.
     */
    private static HashMap<String /*GLProfile_name*/, GLProfile> getProfileMap(AbstractGraphicsDevice device, boolean throwExceptionOnZeroProfile) 
        throws GLException 
    {
        initSingleton();

        if(null==defaultDevice) { // avoid NPE and notify of incomplete initialization
            throw new GLException("No default device available");
        }
        
        if(null==device) {
            device = defaultDevice;
        }
        
        final String deviceKey = device.getUniqueID();
        HashMap<String /*GLProfile_name*/, GLProfile> map = deviceConn2ProfileMap.get(deviceKey);
        if( null != map ) {
            return map;
        }
        if( !initProfilesForDevice(device) ) {
            if( throwExceptionOnZeroProfile ) {
                throw new GLException("No Profile available for "+device);
            } else {
                return null;
            }
        }
        map = deviceConn2ProfileMap.get(deviceKey);
        if( null == map && throwExceptionOnZeroProfile ) {
            throw new InternalError("initProfilesForDevice(..) didn't setProfileMap(..) for "+device);
        }
        return map;
    }

    private static void setProfileMap(AbstractGraphicsDevice device, HashMap<String /*GLProfile_name*/, GLProfile> mappedProfiles) {
        synchronized ( deviceConn2ProfileMap ) {
            deviceConn2ProfileMap.put(device.getUniqueID(), mappedProfiles);
        }
    }

    private GLProfile(String profile, GLProfile profileImpl, boolean isHardwareRasterizer) {
        this.profile = profile;
        this.profileImpl = profileImpl;
        this.isHardwareRasterizer = isHardwareRasterizer;
    }

    private final GLProfile profileImpl;
    private final String profile;
    private final boolean isHardwareRasterizer;
}