diff options
author | Sven Gothel <[email protected]> | 2015-08-30 02:30:26 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-08-30 02:30:26 +0200 |
commit | 3ac457a3a9074a70bf428bb6a5674b8f70d268b1 (patch) | |
tree | 8e2bf74c9345bd8698a4a5ffcd9b365d30a84ed9 | |
parent | 365d273115a98ab38c454608448c6639c45b5f74 (diff) |
Bug 1203: Optimize OpenGL Profile probing/mapping (Skip redundant queries)
Via GLDrawableFactory[Impl] the following details are considered
while GLContextImpl.mapGLVersions(..):
- hasOpenGLDesktopSupport
If false, skip OpenGL Desktop queries
- hasOpenGLESSupport
If false, skip OpenGL ES queries
- hasMajorMinorCreateContextARB
If false, reduce [maxMajor.maxMinor..minMajor.minMinor]
iteration, reducing to [maxMajor..minMajor],
usually only one query.
9 files changed, 196 insertions, 52 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java index 7d78e3409..51da34ce0 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java @@ -421,6 +421,18 @@ public abstract class GLDrawableFactory { public abstract GLRendererQuirks getRendererQuirks(AbstractGraphicsDevice device, final GLProfile glp); /** + * Method returns {@code true} if underlying implementation may support native desktop OpenGL, + * otherwise {@code false}. + */ + public abstract boolean hasOpenGLDesktopSupport(); + + /** + * Method returns {@code true} if underlying implementation may support native embedded OpenGL ES, + * otherwise {@code false}. + */ + public abstract boolean hasOpenGLESSupport(); + + /** * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null */ public static GLDrawableFactory getDesktopFactory() { diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index a5e6bf353..45cfc6bcc 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -1117,8 +1117,11 @@ public abstract class GLContextImpl extends GLContext { private final boolean mapGLVersions(final AbstractGraphicsDevice device) { synchronized (GLContext.deviceVersionAvailable) { + final boolean hasOpenGLESSupport = drawable.getFactory().hasOpenGLESSupport(); + final boolean hasOpenGLDesktopSupport = drawable.getFactory().hasOpenGLDesktopSupport(); + final boolean hasMinorVersionSupport = drawable.getFactoryImpl().hasMajorMinorCreateContextARB(); if (DEBUG) { - System.err.println(getThreadName() + ": createContextARB-MapGLVersions START on "+device); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions START (GLDesktop "+hasOpenGLDesktopSupport+", GLES "+hasOpenGLESSupport+", minorVersion "+hasMinorVersionSupport+") on "+device); } final long t0 = ( DEBUG ) ? System.nanoTime() : 0; boolean success = false; @@ -1132,9 +1135,9 @@ public abstract class GLContextImpl extends GLContext { boolean hasES2 = false; boolean hasES1 = false; - if( (device instanceof EGLGraphicsDevice) && !GLProfile.disableOpenGLES ) { + if( hasOpenGLESSupport && !GLProfile.disableOpenGLES ) { if( !hasES3) { - hasES3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_ES); // ES3 + hasES3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_ES, hasMinorVersionSupport); // ES3 success |= hasES3; if( hasES3 ) { if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { @@ -1148,7 +1151,7 @@ public abstract class GLContextImpl extends GLContext { } } if( !hasES2) { - hasES2 = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_ES); // ES2 + hasES2 = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_ES, hasMinorVersionSupport); // ES2 success |= hasES2; if( hasES2 ) { if( ctxVersion.getMajor() >= 3 && hasRendererQuirk(GLRendererQuirks.GLES3ViaEGLES2Config)) { @@ -1158,7 +1161,7 @@ public abstract class GLContextImpl extends GLContext { } } if( !hasES1) { - hasES1 = createContextARBMapVersionsAvailable(device, 1, CTX_PROFILE_ES); // ES1 + hasES1 = createContextARBMapVersionsAvailable(device, 1, CTX_PROFILE_ES, hasMinorVersionSupport); // ES1 success |= hasES1; if( hasES1 ) { resetStates(false); // clean context states, since creation was temporary @@ -1174,8 +1177,8 @@ public abstract class GLContextImpl extends GLContext { /** * OSX 10.9 GLRendererQuirks.GL4NeedsGL3Request, quirk is added as usual @ setRendererQuirks(..) */ - if( !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore && !hasGL4 && !hasGL3 ) { - hasGL3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE); // GL3 + if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore && !hasGL4 && !hasGL3 ) { + hasGL3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE, hasMinorVersionSupport); // GL3 success |= hasGL3; if( hasGL3 ) { final boolean isHWAccel = 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ); @@ -1191,9 +1194,9 @@ public abstract class GLContextImpl extends GLContext { } } } - if( !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore ) { + if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore ) { if( !hasGL4 ) { - hasGL4 = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_CORE); // GL4 + hasGL4 = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_CORE, hasMinorVersionSupport); // GL4 success |= hasGL4; if( hasGL4 ) { if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { @@ -1207,16 +1210,16 @@ public abstract class GLContextImpl extends GLContext { } } if( !hasGL3 ) { - hasGL3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE); // GL3 + hasGL3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE, hasMinorVersionSupport); // GL3 success |= hasGL3; if( hasGL3 ) { resetStates(false); // clean this context states, since creation was temporary } } } - if( !GLProfile.disableOpenGLDesktop ) { + if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop ) { if( !hasGL4bc ) { - hasGL4bc = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_COMPAT); // GL4bc + hasGL4bc = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_COMPAT, hasMinorVersionSupport); // GL4bc success |= hasGL4bc; if( hasGL4bc ) { if( !hasGL4 ) { // last chance .. ignore hw-accel @@ -1240,7 +1243,7 @@ public abstract class GLContextImpl extends GLContext { } } if( !hasGL3bc ) { - hasGL3bc = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_COMPAT); // GL3bc + hasGL3bc = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_COMPAT, hasMinorVersionSupport); // GL3bc success |= hasGL3bc; if( hasGL3bc ) { if(!hasGL3) { // last chance .. ignore hw-accel @@ -1258,7 +1261,7 @@ public abstract class GLContextImpl extends GLContext { } } if( !hasGL2 ) { - hasGL2 = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_COMPAT); // GL2 + hasGL2 = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_COMPAT, hasMinorVersionSupport); // GL2 success |= hasGL2; if( hasGL2 ) { resetStates(false); // clean this context states, since creation was temporary @@ -1284,7 +1287,8 @@ public abstract class GLContextImpl extends GLContext { * Note: Since context creation is temporary, caller need to issue {@link #resetStates(boolean)}, if creation was successful, i.e. returns true. * This method does not reset the states, allowing the caller to utilize the state variables. **/ - private final boolean createContextARBMapVersionsAvailable(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile) { + private final boolean createContextARBMapVersionsAvailable(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile, + final boolean hasMinorVersionSupport) { long _context; int ctp = CTX_IS_ARB_CREATED | reqProfile; @@ -1296,22 +1300,43 @@ public abstract class GLContextImpl extends GLContext { final int major[] = new int[1]; final int minor[] = new int[1]; - if( CTX_PROFILE_ES == reqProfile ) { - // ES3, ES2 or ES1 - maxMajor=reqMajor; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); - minMajor=reqMajor; minMinor=0; + if( hasMinorVersionSupport ) { + if( CTX_PROFILE_ES == reqProfile ) { + // ES3, ES2 or ES1 + maxMajor=reqMajor; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); + minMajor=reqMajor; minMinor=0; + } else { + if( 4 == reqMajor ) { + maxMajor=4; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); + minMajor=4; minMinor=0; + } else if( 3 == reqMajor ) { + maxMajor=3; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); + minMajor=3; minMinor=1; + } else /* if( glp.isGL2() ) */ { + // our minimum desktop OpenGL runtime requirements are 1.1, + // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts + maxMajor=3; maxMinor=0; + minMajor=2; minMinor=0; + } + } } else { - if( 4 == reqMajor ) { - maxMajor=4; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); - minMajor=4; minMinor=0; - } else if( 3 == reqMajor ) { - maxMajor=3; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); - minMajor=3; minMinor=1; - } else /* if( glp.isGL2() ) */ { - // our minimum desktop OpenGL runtime requirements are 1.1, - // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts - maxMajor=3; maxMinor=0; - minMajor=2; minMinor=0; + if( CTX_PROFILE_ES == reqProfile ) { + // ES3, ES2 or ES1 + maxMajor=reqMajor; maxMinor=0; + minMajor=reqMajor; minMinor=0; + } else { + if( 4 == reqMajor ) { + maxMajor=4; maxMinor=0; + minMajor=4; minMinor=0; + } else if( 3 == reqMajor ) { + maxMajor=3; maxMinor=1; + minMajor=3; minMinor=1; + } else /* if( glp.isGL2() ) */ { + // our minimum desktop OpenGL runtime requirements are 1.1, + // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts + maxMajor=2; maxMinor=0; + minMajor=2; minMinor=0; + } } } _context = createContextARBVersions(0, true, ctp, @@ -1358,11 +1383,11 @@ public abstract class GLContextImpl extends GLContext { } private final long createContextARBVersions(final long share, final boolean direct, final int ctxOptionFlags, - final int majorMax, final int minorMax, - final int majorMin, final int minorMin, + final int maxMajor, final int maxMinor, + final int minMajor, final int minMinor, final int major[], final int minor[]) { - major[0]=majorMax; - minor[0]=minorMax; + major[0]=maxMajor; + minor[0]=maxMinor; long _context=0; int i=0; @@ -1370,7 +1395,7 @@ public abstract class GLContextImpl extends GLContext { if (DEBUG) { i++; System.err.println(getThreadName() + ": createContextARBVersions."+i+": share "+share+", direct "+direct+ - ", version "+major[0]+"."+minor[0]+", major["+majorMin+".."+majorMax+"], minor["+minorMin+".."+minorMax+"]"); + ", version "+major[0]+"."+minor[0]+" ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]"); } _context = createContextARBImpl(share, direct, ctxOptionFlags, major[0], minor[0]); @@ -1383,12 +1408,12 @@ public abstract class GLContextImpl extends GLContext { } } - } while ( ( major[0]>majorMin || major[0]==majorMin && minor[0] >minorMin ) && // #1 check whether version is above lower limit + } while ( ( major[0]>minMajor || major[0]==minMajor && minor[0] >minMinor ) && // #1 check whether version is above lower limit GLContext.decrementGLVersion(ctxOptionFlags, major, minor) // #2 decrement version ); if (DEBUG) { System.err.println(getThreadName() + ": createContextARBVersions.X: ctx "+toHexString(_context)+", share "+share+", direct "+direct+ - ", version "+major[0]+"."+minor[0]+", major["+majorMin+".."+majorMax+"], minor["+minorMin+".."+minorMax+"]"); + ", version "+major[0]+"."+minor[0]+" ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]"); } return _context; } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 472172c75..dfe6bdd9f 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -230,6 +230,15 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { } /** + * Method returns {@code true} if underlying {@link #createContextARBImpl(long, boolean, int, int, int) <i>ARB context creation</i>} + * supports {@code major} and {@code minor} version number. + * <p> + * Otherwise only the {@code major} version number is supported for context creation. + * </p> + */ + public abstract boolean hasMajorMinorCreateContextARB(); + + /** * Returns the shared device mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, * either a preexisting or newly created, or <code>null</code> if creation failed or not supported.<br> * Creation of the shared context is tried only once. diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index f0040f989..1910fbe72 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -168,7 +168,7 @@ public class EGLContext extends GLContextImpl { final long eglConfig = config.getNativeConfig(); final EGLDrawableFactory factory = (EGLDrawableFactory) drawable.getFactoryImpl(); - final boolean hasFullOpenGLAPISupport = factory.hasFullOpenGLAPISupport(); + final boolean hasFullOpenGLAPISupport = factory.hasOpenGLDesktopSupport(); final boolean useKHRCreateContext = factory.hasDefaultDeviceKHRCreateContext(); final boolean ctDesktopGL = 0 == ( GLContext.CTX_PROFILE_ES & ctp ); final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; @@ -177,9 +177,8 @@ public class EGLContext extends GLContextImpl { if(DEBUG) { System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: Start "+getGLVersion(reqMajor, reqMinor, ctp, "@creation") - + ", OpenGL API Support "+factory.hasOpenGLAPISupport() + ", useKHRCreateContext "+useKHRCreateContext - + ", Full OpenGL API Support "+hasFullOpenGLAPISupport + + ", OpenGL API Support "+hasFullOpenGLAPISupport + ", device "+device); } if ( 0 == eglDisplay ) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index dc7b35bf2..2e5ee0854 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -899,17 +899,14 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return defaultDeviceEGLFeatures.hasKHRCreateContext; } /** - * Method returns {@code true} if {@code EGL_OpenGL_API} is supported, - * otherwise method returns {@code false}. + * {@inheritDoc} + * <p> + * This factory may support native desktop OpenGL if {@link EGL#EGL_CLIENT_APIS} contains {@code OpenGL} + * <i>and</i> if {@code EGL_KHR_create_context} extension is supported. + * </p> */ - public final boolean hasOpenGLAPISupport() { - return defaultDeviceEGLFeatures.hasGLAPI; - } - /** - * Method returns {@code true} if {@code EGL_OpenGL_API} and {@code EGL_KHR_create_context} is supported, - * otherwise method returns {@code false}. - */ - public final boolean hasFullOpenGLAPISupport() { + @Override + public final boolean hasOpenGLDesktopSupport() { /** * It has been experienced w/ Mesa 10.3.2 (EGL 1.4/Gallium) * that even though initial OpenGL context can be created w/o 'EGL_KHR_create_context', @@ -920,6 +917,27 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { defaultDeviceEGLFeatures.hasGLAPI && defaultDeviceEGLFeatures.hasKHRCreateContext; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * Return true if {@code EGL_KHR_create_context} extension is supported, + * see {@link #hasDefaultDeviceKHRCreateContext()}. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { + return hasDefaultDeviceKHRCreateContext(); + } + @Override public final AbstractGraphicsDevice getDefaultDevice() { return defaultDevice; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 120de4a13..871067f4c 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -335,6 +335,33 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return null; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * Always returns true. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return true; } + @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return MacOSXCGLGraphicsConfiguration.getAvailableCapabilities(this, device); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index 8fd5454d2..652184e7e 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -443,6 +443,33 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { return null; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * Always returns true. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return true; } + @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return WindowsWGLGraphicsConfigurationFactory.getAvailableCapabilities(this, device); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 7121776f6..a03ce1641 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -379,6 +379,33 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return 0; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * Always returns true. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return true; } + @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return X11GLXGraphicsConfigurationFactory.getAvailableCapabilities(this, device); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java index d940510cb..fe3ba91e3 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java @@ -185,7 +185,7 @@ public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { } @Test - public void test11ES2OnGL() throws InterruptedException { + public void test11ES2OnDesktop() throws InterruptedException { final GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); if( null == factory ) { System.err.println("Desktop Factory n/a"); @@ -207,7 +207,7 @@ public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { } @Test - public void test12GLOnGL() throws InterruptedException { + public void test12GLOnDesktop() throws InterruptedException { final GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); if( null == factory ) { System.err.println("Desktop Factory n/a"); |