summaryrefslogtreecommitdiffstats
path: root/src/nativewindow/classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/nativewindow/classes')
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java18
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java11
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java8
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/drm/DRMUtil.java154
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/drm/DrmMode.java304
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/drm/GBMDummyUpstreamSurfaceHook.java105
6 files changed, 593 insertions, 7 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java
index 929af054e..5214dbf3d 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java
@@ -427,6 +427,24 @@ public abstract class GraphicsConfigurationFactory {
}
}
+ /**
+ * Called by {@link #chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, CapabilitiesChooser, AbstractGraphicsScreen, int)}
+ * post argument validation within {@link AbstractGraphicsDevice#lock()}ed segment.
+ *
+ * @param capsChosen the intermediate chosen capabilities to be refined by this implementation, may be equal to capsRequested
+ * @param capsRequested the original requested capabilities
+ * @param chooser the choosing implementation
+ * @param screen the referring Screen
+ * @param nativeVisualID if not {@link VisualIDHolder#VID_UNDEFINED} it reflects a pre-chosen visualID of the native platform's windowing system.
+ * @return the complete GraphicsConfiguration
+ *
+ * @throws IllegalArgumentException if the data type of the passed
+ * AbstractGraphicsDevice is not supported by this
+ * NativeWindowFactory.
+ * @throws NativeWindowException if any window system-specific errors caused
+ * the selection of the graphics configuration to fail.
+ * @see #chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, CapabilitiesChooser, AbstractGraphicsScreen, int)
+ */
protected abstract AbstractGraphicsConfiguration
chooseGraphicsConfigurationImpl(CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested,
CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID)
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
index a41e9c349..d4249d404 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
@@ -86,8 +86,8 @@ public abstract class NativeWindowFactory {
/** Wayland/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
public static final String TYPE_WAYLAND = ".wayland";
- /** GBM/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
- public static final String TYPE_EGL_GBM = ".egl.gbm";
+ /** DRM/GBM type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
+ public static final String TYPE_DRM_GBM = ".egl.gbm"; // We leave the sub-package name as .egl.gbm for NEWT as it uses EGL
/** OpenKODE/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
public static final String TYPE_EGL = ".egl";
@@ -128,6 +128,8 @@ public abstract class NativeWindowFactory {
private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ;
/** {@link jogamp.nativewindow.x11.X11Util} implements {@link ToolkitProperties}. */
private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util";
+ /** {@link jogamp.nativewindow.drm.DRMUtil} implements {@link ToolkitProperties}. */
+ private static final String DRMUtilClassName = "jogamp.nativewindow.drm.DRMUtil";
/** {@link jogamp.nativewindow.macosx.OSXUtil} implements {@link ToolkitProperties}. */
private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil";
/** {@link jogamp.nativewindow.ios.IOSUtil} implements {@link ToolkitProperties}. */
@@ -181,7 +183,7 @@ public abstract class NativeWindowFactory {
return TYPE_WAYLAND;
}
if( guessGBM(false) ) {
- return TYPE_EGL_GBM;
+ return TYPE_DRM_GBM;
}
if( BcmVCArtifacts.guessVCIVUsed(false) ) {
return TYPE_BCM_VC_IV;
@@ -259,6 +261,9 @@ public abstract class NativeWindowFactory {
case TYPE_X11:
clazzName = X11UtilClassName;
break;
+ case TYPE_DRM_GBM:
+ clazzName = DRMUtilClassName;
+ break;
case TYPE_WINDOWS:
clazzName = GDIClassName;
break;
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java b/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java
index 69bfe50f8..62b73d230 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java
@@ -40,13 +40,13 @@ import java.util.Comparator;
public interface VisualIDHolder {
public enum VIDType {
- // Generic Values
+ /** Generic Values */
INTRINSIC(0), NATIVE(1),
- // EGL Values
+ /** EGL Values */
EGL_CONFIG(10),
- // X11 Values
+ /** X11 Values */
X11_XVISUAL(20), X11_FBCONFIG(21),
- // Windows Values
+ /** Windows Values */
WIN32_PFD(30);
public final int id;
diff --git a/src/nativewindow/classes/jogamp/nativewindow/drm/DRMUtil.java b/src/nativewindow/classes/jogamp/nativewindow/drm/DRMUtil.java
new file mode 100644
index 000000000..176ebccb0
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/drm/DRMUtil.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright 2019 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.nativewindow.drm;
+
+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;
+
+/**
+ * DRM and GBM utility
+ */
+public class DRMUtil implements ToolkitProperties {
+ /* pp */ static final boolean DEBUG = Debug.debug("DRMUtil");
+
+ /** FIXME: Add support for other OS implementing DRM/GBM, e.g. FreeBSD, OpenBSD, ..? */
+ private static final String dri0Linux = "/dev/dri/card0";
+
+ private static volatile boolean isInit = false;
+ /** DRM file descriptor, valid if >= 0 */
+ private static int drmFd = -1;
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static void initSingleton() {
+ if(!isInit) {
+ synchronized(DRMUtil.class) {
+ if(!isInit) {
+ isInit = true;
+ if(DEBUG) {
+ System.out.println("DRMUtil.initSingleton()");
+ }
+ if(!NWJNILibLoader.loadNativeWindow("drm")) {
+ throw new NativeWindowException("NativeWindow DRM native library load error.");
+ }
+ if( initialize0(DEBUG) ) {
+ drmFd = DRMLib.drmOpenFile(dri0Linux);
+ }
+ if(DEBUG) {
+ System.err.println("DRMUtil.initSingleton(): OK "+(0 <= drmFd)+", drmFd "+drmFd+"]");
+ if( 0 <= drmFd ) {
+ final DrmMode d = DrmMode.create(drmFd, true);
+ d.print(System.err);
+ d.destroy();
+ }
+ // Thread.dumpStack();
+ }
+ }
+ }
+ }
+ }
+
+ /** Return the global DRM file descriptor */
+ public static int getDrmFd() { return drmFd; }
+
+ /**
+ * Cleanup resources.
+ * <p>
+ * Called by {@link NativeWindowFactory#shutdown()}
+ * </p>
+ * @see ToolkitProperties
+ */
+ public static void shutdown() {
+ if(isInit) {
+ synchronized(DRMUtil.class) {
+ if(isInit) {
+ final boolean isJVMShuttingDown = NativeWindowFactory.isJVMShuttingDown() ;
+ if( DEBUG ) {
+ System.err.println("DRMUtil.Display: Shutdown (JVM shutdown: "+isJVMShuttingDown+")");
+ if(DEBUG) {
+ ExceptionUtils.dumpStack(System.err);
+ }
+ }
+
+ // Only at JVM shutdown time, since AWT impl. seems to
+ // dislike closing of X11 Display's (w/ ATI driver).
+ if( isJVMShuttingDown ) {
+ if( 0 <= drmFd ) {
+ DRMLib.drmClose(drmFd);
+ drmFd = -1;
+ }
+ isInit = false;
+ shutdown0();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean requiresToolkitLock() {
+ return true;
+ }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean hasThreadingIssues() {
+ return false;
+ }
+
+ static int fourcc_code(final char a, final char b, final char c, final char d) {
+ // return ( (int)(a) | ((int)(b) << 8) | ((int)(c) << 16) | ((int)(d) << 24) );
+ return ( (a) | ((b) << 8) | ((c) << 16) | ((d) << 24) );
+ }
+ /** [31:0] x:R:G:B 8:8:8:8 little endian */
+ public static final int GBM_FORMAT_XRGB8888 = fourcc_code('X', 'R', '2', '4');
+ /** [31:0] A:R:G:B 8:8:8:8 little endian */
+ public static final int GBM_FORMAT_ARGB8888 = fourcc_code('A', 'R', '2', '4');
+
+ private DRMUtil() {}
+
+ 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();
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/drm/DrmMode.java b/src/nativewindow/classes/jogamp/nativewindow/drm/DrmMode.java
new file mode 100644
index 000000000..44b2a1327
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/drm/DrmMode.java
@@ -0,0 +1,304 @@
+/**
+ * Copyright 2019 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.nativewindow.drm;
+
+import java.io.PrintStream;
+import java.nio.IntBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.jogamp.nativewindow.NativeWindowException;
+
+import jogamp.nativewindow.drm.DRMLib;
+import jogamp.nativewindow.drm.drmModeConnector;
+import jogamp.nativewindow.drm.drmModeEncoder;
+import jogamp.nativewindow.drm.drmModeModeInfo;
+import jogamp.nativewindow.drm.drmModeRes;
+
+/**
+ * Describing a DRM adapter's connected {@link drmModeConnector}
+ * and it's {@link drmModeModeInfo}, {@link drmModeEncoder} and CRT index.
+ */
+public class DrmMode {
+ /** DRM file descriptor, valid if >= 0 */
+ public final int drmFd;
+ /** Number of connected {@link drmModeConnector}s and hence length of all arrays within this instance. */
+ public final int count;
+ /** Connected {@link drmModeConnector}, multiple outputs supported. Array can be of length zero if none is connected. */
+ private final drmModeConnector[] connectors;
+ /** Selected current mode {@link drmModeModeInfo}. Array index matches the {@link #connectors}. */
+ private final drmModeModeInfo[] modes;
+ /** Selected {@link drmModeEncoder}. Array index matches the {@link #connectors}. */
+ private final drmModeEncoder[] encoder;
+ /** Selected CRT IDs. Array index matches the {@link #connectors}. */
+ private final int[] crtc_ids;
+ /** Selected CRT indices. Array index matches the {@link #connectors}. */
+ private final int[] crtc_indices;
+ /** boolean indicating that instance data is valid reflecting native DRM data and has not been {@link #destroy()}ed. */
+ private volatile boolean valid;
+
+ private DrmMode(final int drmFd, final int count) {
+ this.drmFd = drmFd;
+ this.count = count;
+ this.connectors = new drmModeConnector[count];
+ this.modes = new drmModeModeInfo[count];
+ this.encoder = new drmModeEncoder[count];
+ this.crtc_ids = new int[count];
+ this.crtc_indices = new int[count];
+ this.valid = false;
+ }
+
+ public void print(final PrintStream out) {
+ for(int i=0; i<count; i++) {
+ print(out, i);
+ }
+ }
+ public void print(final PrintStream out, final int connectorIdx) {
+ final drmModeConnector c = connectors[connectorIdx];
+ out.printf("Connector[%d]: id[con 0x%x, enc 0x%x], type %d[id 0x%x], connection %d, dim %dx%x mm, modes %d, encoders %d\n",
+ connectorIdx, c.getConnector_id(), c.getEncoder_id(),
+ c.getConnector_type(), c.getConnector_type_id(), c.getConnection(), c.getMmWidth(), c.getMmHeight(),
+ c.getCount_modes(), c.getCount_encoders());
+ final drmModeModeInfo m = modes[connectorIdx];
+ System.err.printf( "Connector[%d].Mode: clock %d, %dx%d @ %d Hz, type %d, name <%s>\n",
+ connectorIdx, m.getClock(), m.getHdisplay(), m.getVdisplay(), m.getVrefresh(),
+ m.getType(), m.getNameAsString());
+ final drmModeEncoder e = encoder[connectorIdx];
+ System.err.printf( "Connector[%d].Encoder: id 0x%x, type %d, crtc_id 0x%x, possible[crtcs %d, clones %d]\n",
+ connectorIdx, e.getEncoder_id(), e.getEncoder_type(), e.getCrtc_id(),
+ e.getPossible_crtcs(), e.getPossible_clones());
+ }
+
+ /**
+ * Collecting all connected {@link drmModeConnector}
+ * and it's {@link drmModeModeInfo}, {@link drmModeEncoder} and CRT index.
+ *
+ * @param drmFd the DRM file descriptor
+ * @param preferNativeMode chose {@link DRMLib#DRM_MODE_TYPE_PREFERRED}
+ */
+ public static DrmMode create(final int drmFd, final boolean preferNativeMode) {
+ final drmModeRes resources = DRMLib.drmModeGetResources(drmFd);
+ if( null == resources ) {
+ throw new NativeWindowException("drmModeGetResources failed");
+ }
+ DrmMode res = null;
+ try {
+ {
+ final List<drmModeConnector> _connectors = new ArrayList<drmModeConnector>();
+ final IntBuffer _connectorIDs = resources.getConnectors();
+ if(DRMUtil.DEBUG) {
+ for(int i=0; i<_connectorIDs.limit(); i++) {
+ final drmModeConnector c = DRMLib.drmModeGetConnector(drmFd, _connectorIDs.get(i));
+ final boolean chosen = DRMLib.DRM_MODE_CONNECTED == c.getConnection();
+ System.err.printf("Connector %d/%d chosen %b,: id[con 0x%x, enc 0x%x], type %d[id 0x%x], connection %d, dim %dx%x mm, modes %d, encoders %d\n",
+ i, _connectorIDs.limit(), chosen, c.getConnector_id(), c.getEncoder_id(),
+ c.getConnector_type(), c.getConnector_type_id(), c.getConnection(), c.getMmWidth(), c.getMmHeight(),
+ c.getCount_modes(), c.getCount_encoders());
+ DRMLib.drmModeFreeConnector(c);
+ }
+ }
+ drmModeConnector con = null;
+ for(int i=0; i<_connectorIDs.limit(); i++) {
+ con = DRMLib.drmModeGetConnector(drmFd, _connectorIDs.get(i));
+ if( DRMLib.DRM_MODE_CONNECTED == con.getConnection() ) {
+ _connectors.add(con);
+ } else {
+ DRMLib.drmModeFreeConnector(con);
+ con = null;
+ }
+ }
+ res = new DrmMode(drmFd, _connectors.size());
+ _connectors.toArray(res.connectors);
+ }
+ for(int k=0; k<res.count; k++) {
+ final drmModeModeInfo _modes[] = res.connectors[k].getModes(0, new drmModeModeInfo[res.connectors[k].getCount_modes()]);
+ drmModeModeInfo _mode = null;
+ {
+ int maxArea = 0;
+ int j=0;
+ for(int i=0; i<_modes.length; i++) {
+ final drmModeModeInfo m = _modes[i];
+ final int area = m.getHdisplay() * m.getVdisplay();
+ if( preferNativeMode && m.getType() == DRMLib.DRM_MODE_TYPE_PREFERRED ) {
+ _mode = m;
+ maxArea = Integer.MAX_VALUE;
+ j = i;
+ // only continue loop for DEBUG verbosity
+ } else if( area > maxArea ) {
+ _mode = m;
+ maxArea = area;
+ j = i;
+ }
+ if( DRMUtil.DEBUG ) {
+ System.err.printf( "Connector[%d].Mode %d/%d (max-chosen %d): clock %d, %dx%d @ %d Hz, type %d, name <%s>\n",
+ k, i, _modes.length, j,
+ m.getClock(), m.getHdisplay(), m.getVdisplay(), m.getVrefresh(),
+ m.getType(), m.getNameAsString());
+ }
+ }
+ }
+ if( null == _mode ) {
+ throw new NativeWindowException("could not find mode");
+ }
+ res.modes[k] = _mode;
+ }
+ {
+ final IntBuffer encoderIDs = resources.getEncoders();
+ for(int k=0; k<res.count; k++) {
+ if( DRMUtil.DEBUG ) {
+ for (int i = 0; i < encoderIDs.limit(); i++) {
+ final drmModeEncoder e = DRMLib.drmModeGetEncoder(drmFd, encoderIDs.get(i));
+ final boolean chosen = e.getEncoder_id() == res.connectors[k].getEncoder_id();
+ System.err.printf( "Connector[%d].Encoder %d/%d chosen %b: id 0x%x, type %d, crtc_id 0x%x, possible[crtcs %d, clones %d]\n",
+ k, i, encoderIDs.limit(), chosen,
+ e.getEncoder_id(), e.getEncoder_type(), e.getCrtc_id(),
+ e.getPossible_crtcs(), e.getPossible_clones());
+ DRMLib.drmModeFreeEncoder(e);
+ }
+ }
+ drmModeEncoder e = null;
+ for (int i = 0; i < encoderIDs.limit(); i++) {
+ e = DRMLib.drmModeGetEncoder(drmFd, encoderIDs.get(i));
+ if( e.getEncoder_id() == res.connectors[k].getEncoder_id() ) {
+ break;
+ } else {
+ DRMLib.drmModeFreeEncoder(e);
+ e = null;
+ }
+ }
+ if( null == e ) {
+ throw new NativeWindowException("could not find encoder");
+ }
+ res.encoder[k] = e;
+ }
+ }
+ {
+ final IntBuffer crtcs = resources.getCrtcs();
+ for(int k=0; k<res.count; k++) {
+ int idx = -1;
+ for(int i=0; i<crtcs.limit(); i++) {
+ if( crtcs.get(i) == res.encoder[k].getCrtc_id() ) {
+ idx = i;
+ break;
+ }
+ }
+ if( 0 > idx ) {
+ throw new NativeWindowException("could not find crtc index");
+ }
+ res.crtc_ids[k] = crtcs.get(idx);
+ res.crtc_indices[k] = idx;
+ }
+ }
+ } catch (final Throwable t) {
+ if( null != res ) {
+ res.destroy();
+ res = null;
+ }
+ throw t;
+ } finally {
+ DRMLib.drmModeFreeResources(resources);
+ }
+ res.valid = true;
+ return res;
+ }
+
+ /**
+ * Returns whether instance data is valid reflecting native DRM data and has not been {@link #destroy()}ed.
+ */
+ public final boolean isValid() {
+ return valid;
+ }
+ private final void checkValid() {
+ if( !valid ) {
+ throw new IllegalStateException("Instance is invalid");
+ }
+ }
+
+
+ /**
+ * Frees all native DRM resources collected by one of the static methods like {@link #create(int, boolean)}.
+ * <p>
+ * Method should be issued before shutting down or releasing the {@link #drmFd} via {@link DRMLib#drmClose(int)}.
+ * </p>
+ */
+ public final void destroy() {
+ if( valid ) {
+ synchronized( this ) {
+ if( valid ) {
+ valid = false;
+ for(int i=0; i<count; i++) {
+ if( null != encoder[i] ) {
+ DRMLib.drmModeFreeEncoder(encoder[i]);
+ }
+ if( null != connectors[i]) {
+ DRMLib.drmModeFreeConnector(connectors[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns an array for each connected {@link drmModeConnector}s.
+ * <p>
+ * Returned array length is zero if no {@link drmModeConnector} is connected.
+ * </p>
+ * @throws IllegalStateException if instance is not {@link #isValid()}.
+ */
+ public final drmModeConnector[] getConnectors() throws IllegalStateException
+ { checkValid(); return connectors; }
+
+ /**
+ * Returns an array of {@link drmModeModeInfo} for each connected {@link #getConnectors()}'s current mode.
+ * @throws IllegalStateException if instance is not {@link #isValid()}.
+ */
+ public final drmModeModeInfo[] getModes() throws IllegalStateException
+ { checkValid(); return modes; }
+
+ /**
+ * Returns an array of {@link drmModeEncoder} for each connected {@link #getConnectors()}.
+ * @throws IllegalStateException if instance is not {@link #isValid()}.
+ */
+ public final drmModeEncoder[] getEncoder() throws IllegalStateException
+ { checkValid(); return encoder; }
+
+ /**
+ * Returns an array of selected CRT IDs for each connected {@link #getConnectors()}.
+ * @throws IllegalStateException if instance is not {@link #isValid()}.
+ */
+ public final int[] getCrtcIDs() throws IllegalStateException
+ { checkValid(); return crtc_ids; }
+
+ /**
+ * Returns an array of selected CRT indices for each connected {@link #getConnectors()}.
+ * @throws IllegalStateException if instance is not {@link #isValid()}.
+ */
+ public final int[] getCrtcIndices() throws IllegalStateException
+ { checkValid(); return crtc_indices; }
+} \ No newline at end of file
diff --git a/src/nativewindow/classes/jogamp/nativewindow/drm/GBMDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/drm/GBMDummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..c237e6802
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/drm/GBMDummyUpstreamSurfaceHook.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright 2019 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.nativewindow.drm;
+
+import com.jogamp.nativewindow.AbstractGraphicsDevice;
+import com.jogamp.nativewindow.NativeSurface;
+import com.jogamp.nativewindow.NativeWindowException;
+import com.jogamp.nativewindow.ProxySurface;
+import com.jogamp.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+public class GBMDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ private long gbmDevice = 0;
+
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public GBMDummyUpstreamSurfaceHook(final int width, final int height) {
+ super(width, height);
+ }
+
+ @Override
+ public final void create(final ProxySurface s) {
+ final AbstractGraphicsDevice gd = s.getGraphicsConfiguration().getScreen().getDevice();
+ final int visualID = DRMUtil.GBM_FORMAT_XRGB8888;
+ gd.lock();
+ try {
+ if( 0 == s.getSurfaceHandle() ) {
+ gbmDevice = DRMLib.gbm_create_device(DRMUtil.getDrmFd());
+ if(0 == gbmDevice) {
+ throw new NativeWindowException("Creating dummy GBM device failed");
+ }
+
+ final long gbmSurface = DRMLib.gbm_surface_create(gbmDevice, 64, 64, visualID,
+ DRMLib.GBM_BO_USE_SCANOUT | DRMLib.GBM_BO_USE_RENDERING);
+ if(0 == gbmSurface) {
+ throw new NativeWindowException("Creating dummy GBM surface failed");
+ }
+ s.setSurfaceHandle(gbmSurface);
+
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE );
+ } finally {
+ gd.unlock();
+ }
+ }
+
+ @Override
+ public final void destroy(final ProxySurface s) {
+ if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ final AbstractGraphicsDevice gd = s.getGraphicsConfiguration().getScreen().getDevice();
+ final long gbmSurface = s.getSurfaceHandle();
+ if( 0 == gbmDevice ) {
+ throw new InternalError("GBM device handle is null");
+ }
+ if( 0 == gbmSurface ) {
+ throw new InternalError("Owns upstream surface, but has no GBM surface: "+s);
+ }
+ gd.lock();
+ try {
+ DRMLib.gbm_surface_destroy(gbmSurface);
+ s.setSurfaceHandle(0);
+
+ DRMLib.gbm_device_destroy(gbmDevice);
+ gbmDevice = 0;
+
+ s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ } finally {
+ gd.unlock();
+ }
+ }
+ }
+}