All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jogamp.nativewindow.x11.X11Util Maven / Gradle / Ivy

/*
 * Copyright (c) 2008 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.
 */

package jogamp.nativewindow.x11;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.jogamp.nativewindow.AbstractGraphicsDevice;
import com.jogamp.nativewindow.NativeWindowException;
import com.jogamp.nativewindow.NativeWindowFactory;

import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NWJNILibLoader;
import jogamp.nativewindow.ToolkitProperties;

import com.jogamp.common.ExceptionUtils;
import com.jogamp.common.util.LongObjectHashMap;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;

/**
 * Contains a thread safe X11 utility to retrieve display connections.
 */
public class X11Util implements ToolkitProperties {
    public static final boolean DEBUG = Debug.debug("X11Util");

    /**
     * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515
     * 

* It is observed that ATI X11 drivers, eg. *

    *
  • fglrx 8.78.6,
  • *
  • fglrx 11.08/8.881 and
  • *
  • fglrx 11.11/8.911
  • *
* are quite sensitive to multiple Display connections. *

*

* With the above drivers closing displays shall happen in the same order as * they were opened, or shall not be closed at all! * If closed, some driver related bug appears and brings down the JVM. *

*

* You may test this, ie just reverse the destroy order below. * See also native test: jogl/test-native/displayMultiple02.c *

*

* Workaround is to not close them at all if driver vendor is ATI * during operation. *

*

* With ATI X11 drivers all connections must be closed at JVM shutdown, * otherwise a SIGSEGV (after JVM safepoint) will be caused. *

*/ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG", true); /** See {@link #ATI_HAS_XCLOSEDISPLAY_BUG}. */ public static final boolean HAS_XCLOSEDISPLAY_BUG = Debug.isPropertyDefined("nativewindow.debug.X11Util.HAS_XCLOSEDISPLAY_BUG", true); /** * See Bug 623 - https://jogamp.org/bugzilla/show_bug.cgi?id=623 */ public static final boolean ATI_HAS_MULTITHREADING_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG", true); public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true); public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); private static String nullDisplayName = null; private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues, or GLRendererQuirks.DontCloseX11Display private static boolean hasThreadingIssues = false; // ATI/AMD X11 driver issues private static final Object setX11ErrorHandlerLock = new Object(); private static final String X11_EXTENSION_ATIFGLRXDRI = "ATIFGLRXDRI"; private static final String X11_EXTENSION_ATIFGLEXTENSION = "ATIFGLEXTENSION"; /** * Called by {@link NativeWindowFactory#initSingleton()} * @see ToolkitProperties */ public static void initSingleton() { if(!isInit) { synchronized(X11Util.class) { if(!isInit) { isInit = true; if(DEBUG) { System.out.println("X11Util.initSingleton()"); } if(!NWJNILibLoader.loadNativeWindow("x11")) { throw new NativeWindowException("NativeWindow X11 native library load error."); } final boolean isInitOK = initialize0( XERROR_STACKDUMP ); final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION; final long dpy = X11Lib.XOpenDisplay(PropertyAccess.getProperty("nativewindow.x11.display.default", true)); if(0 != dpy) { if(XSYNC_ENABLED) { X11Lib.XSynchronize(dpy, true); } try { nullDisplayName = X11Lib.XDisplayString(dpy); hasX11_EXTENSION_ATIFGLRXDRI = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLRXDRI); hasX11_EXTENSION_ATIFGLEXTENSION = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLEXTENSION); } finally { X11Lib.XCloseDisplay(dpy); } } else { nullDisplayName = "nil"; hasX11_EXTENSION_ATIFGLRXDRI = false; hasX11_EXTENSION_ATIFGLEXTENSION = false; } final boolean isATIFGLRX = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION ; hasThreadingIssues = ATI_HAS_MULTITHREADING_BUG && isATIFGLRX; if ( !markAllDisplaysUnclosable ) { markAllDisplaysUnclosable = ( ATI_HAS_XCLOSEDISPLAY_BUG && isATIFGLRX ) || HAS_XCLOSEDISPLAY_BUG; } if(DEBUG) { System.err.println("X11Util.initSingleton(): OK "+isInitOK+"]"+ ",\n\t X11 Display(NULL) <"+nullDisplayName+">"+ ",\n\t XSynchronize Enabled: " + XSYNC_ENABLED+ ",\n\t X11_EXTENSION_ATIFGLRXDRI " + hasX11_EXTENSION_ATIFGLRXDRI+ ",\n\t X11_EXTENSION_ATIFGLEXTENSION " + hasX11_EXTENSION_ATIFGLEXTENSION+ ",\n\t requiresToolkitLock "+requiresToolkitLock()+ ",\n\t hasThreadingIssues "+hasThreadingIssues()+ ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable() ); // Thread.dumpStack(); } } } } } // not exactly thread safe, but good enough for our purpose, // which is to tag a NamedDisplay uncloseable after creation. private static Object globalLock = new Object(); private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name private static List openDisplayList = new ArrayList(); // open, no close attempt private static List reusableDisplayList = new ArrayList(); // close attempt, marked uncloseable, for reuse private static List pendingDisplayList = new ArrayList(); // all open (close attempt or reusable) in creation order private static final HashMap displayXineramaEnabledMap = new HashMap(); /** * Cleanup resources. *

* Called by {@link NativeWindowFactory#shutdown()} *

* @see ToolkitProperties */ public static void shutdown() { if(isInit) { synchronized(X11Util.class) { if(isInit) { final boolean isJVMShuttingDown = NativeWindowFactory.isJVMShuttingDown() ; if( DEBUG || ( ( openDisplayMap.size() > 0 || reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) && ( reusableDisplayList.size() != pendingDisplayList.size() || !markAllDisplaysUnclosable ) ) ) { System.err.println("X11Util.Display: Shutdown (JVM shutdown: "+isJVMShuttingDown+ ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ ", reusable (open, marked uncloseable): "+reusableDisplayList.size()+ ", pending (open in creation order): "+pendingDisplayList.size()+ ")"); if(DEBUG) { ExceptionUtils.dumpStack(System.err); } if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); } if(DEBUG) { if( reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) { X11Util.dumpPendingDisplayConnections(); } } } // Only at JVM shutdown time, since AWT impl. seems to // dislike closing of X11 Display's (w/ ATI driver). if( isJVMShuttingDown ) { synchronized(globalLock) { isInit = false; closePendingDisplayConnections(); openDisplayList.clear(); reusableDisplayList.clear(); pendingDisplayList.clear(); openDisplayMap.clear(); displayXineramaEnabledMap.clear(); shutdown0(); } } } } } } /** * Called by {@link NativeWindowFactory#initSingleton()} * @see ToolkitProperties */ public static final boolean requiresToolkitLock() { return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock per display connection. } /** * Called by {@link NativeWindowFactory#initSingleton()} * @see ToolkitProperties */ public static final boolean hasThreadingIssues() { return hasThreadingIssues; // JOGL impl. may utilize special locking "somewhere" } public static void setX11ErrorHandler(final boolean onoff, final boolean quiet) { synchronized(setX11ErrorHandlerLock) { setX11ErrorHandler0(onoff, quiet); } } public static String getNullDisplayName() { return nullDisplayName; } public static void markAllDisplaysUnclosable() { synchronized(globalLock) { markAllDisplaysUnclosable = true; for(int i=0; i>> 32 ) ; // hi hash32 = h32; } if(DEBUG) { this.creationStack=new Throwable("NamedDisplay Created at:"); } else { this.creationStack=null; } } @Override public final int hashCode() { return hash32; } @Override public final boolean equals(final Object obj) { if(this == obj) { return true; } if(obj instanceof NamedDisplay) { return handle == ((NamedDisplay) obj).handle; } return false; } public final void addRef() { refCount++; } public final void removeRef() { refCount--; } public final String getName() { return name; } public final long getHandle() { return handle; } public final int getRefCount() { return refCount; } public final void setUncloseable(final boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } public final Throwable getCreationStack() { return creationStack; } @Override public String toString() { return "NamedX11Display["+name+", 0x"+Long.toHexString(handle)+", refCount "+refCount+", unCloseable "+unCloseable+"]"; } } /** * Closing pending Display connections in original creation order, if {@link #getMarkAllDisplaysUnclosable()} is true. * * @return number of closed Display connections */ private static int closePendingDisplayConnections() { int num=0; synchronized(globalLock) { if( getMarkAllDisplaysUnclosable() ) { for(int i=0; i "+res); } displayXineramaEnabledMap.put(displayName, Boolean.valueOf(res)); } return res; } private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { ExceptionUtils.dumpStack(System.err); } // Callback for JNI private static native boolean initialize0(boolean debug); private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy