diff options
author | Sven Gothel <[email protected]> | 2019-11-28 02:00:29 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2019-11-28 02:00:29 +0100 |
commit | 3e19c2267500c0c459e7dce8d2087387a56f3296 (patch) | |
tree | 1c6e2e64b7f5f5ee8d6178824dc6ff2e0a3bdbbe /src/newt/classes | |
parent | 976e89ff24da3b2cdf206e8ef8f222f54fb467de (diff) |
Bug 1156 - Implement DRM/GBM Support for JOGL(EGL) and NEWT
Adding new classes DRMLib (gluegen of drm + gbm), DRMUtil and DRMMode GBMDummyUpstreamSurfaceHook
to new package jogamp.nativewindow.drm, allowing full awareness of DRM + GBM within NativeWindow for JOGL + NEWT.
DRMMode replaces the previous native code of collecting drmMode* attributes: active connector, used mode, encoder etc
and also supports multiple active connectors.
DRMUtil handles the global static drmFd (file descriptor), currently only the GNU/Linux DRM device is supported.
GBMDummyUpstreamSurfaceHook provides a simple dummy GBM surface.
NativeWindow provides the new nativewindow_drm.so and nativewindow-os-drm.jar,
which are included in most 'all' jar packages.
build property: setup.addNativeEGLGBM -> setup.addNativeDRMGBM
Changes NativeWindowFactory:
- TYPE_EGL_GBM -> TYPE_DRM_GBM while keeping the package ID of '.egl.gbm' for NEWT (using EGL)
- Initializing DRMUtil at initialization
Changes EGLDrawableFactory:
- Using native GBM device for the default EGL display creation instead of EGL_DEFAULT_DISPLAY.
This resolves issues as seen in Bug 1402, as well in cases w/o surfaceless support.
- GL profile mapping uses surfaceless when available for GBM,
otherwise uses createDummySurfaceImpl (dummy GBM surface via GBMDummyUpstreamSurfaceHook)
- createDummySurfaceImpl uses a dummy GBM surface via GBMDummyUpstreamSurfaceHook
- DesktopGL not available with GBM, see Bug 1401
NEWT's DRM + GBM + EGL Driver
- Using DRMLib, DRMUtil and DRMMode, removed most native code but WindowDriver swapBuffer
- ScreenDriver uses DRMMode, however currently only first connected CRT.
- WindowDriver aligns position and size to screen, positions other than 0/0 causes DRM failure
- WindowDriver reconfigure n/a
NEWT TODO:
- DRM Cursor support (mouse pointer)
- Pointer event handling
Diffstat (limited to 'src/newt/classes')
3 files changed, 159 insertions, 91 deletions
diff --git a/src/newt/classes/jogamp/newt/driver/egl/gbm/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/egl/gbm/DisplayDriver.java index 4d9835826..847532bb4 100644 --- a/src/newt/classes/jogamp/newt/driver/egl/gbm/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/egl/gbm/DisplayDriver.java @@ -31,6 +31,8 @@ import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.opengl.GLProfile; +import jogamp.nativewindow.drm.DRMLib; +import jogamp.nativewindow.drm.DRMUtil; import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; import jogamp.opengl.egl.EGLDisplayUtil; @@ -50,31 +52,23 @@ public class DisplayDriver extends DisplayImpl { if (!WindowDriver.initIDs()) { throw new NativeWindowException("Failed to initialize egl.gbm Window jmethodIDs"); } - drmHandle = initDrm(DEBUG); - } - - static void validateDrm() { - if( 0 == drmHandle ) { - throw new NativeWindowException("Failed to initialize egl.gbm DRM handle"); - } } public static void initSingleton() { // just exist to ensure static init has been run } - private static void shutdownHook() { - freeDrm(drmHandle); - } - public DisplayDriver() { gbmHandle = 0; } @Override protected void createNativeImpl() { - validateDrm(); - gbmHandle = OpenGBMDisplay0(drmHandle); + final int drmFd = DRMUtil.getDrmFd(); + if( 0 > drmFd ) { + throw new NativeWindowException("Failed to initialize DRM"); + } + gbmHandle = DRMLib.gbm_create_device(drmFd); aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(gbmHandle, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); aDevice.open(); } @@ -82,11 +76,10 @@ public class DisplayDriver extends DisplayImpl { @Override protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) { aDevice.close(); - CloseGBMDisplay0(gbmHandle); + DRMLib.gbm_device_destroy(gbmHandle); gbmHandle = 0; } - /* pp */ static final long getDrmHandle() { validateDrm(); return drmHandle; } /* pp */ final long getGBMHandle() { return gbmHandle; } @Override @@ -98,14 +91,8 @@ public class DisplayDriver extends DisplayImpl { // Internals only // private static native boolean initIDs(); - private static native long initDrm(boolean verbose); - private static native void freeDrm(long drmHandle); - - private static native long OpenGBMDisplay0(long drmHandle); - private static native void CloseGBMDisplay0(long gbmHandle); private static native void DispatchMessages0(); - private static final long drmHandle; private long gbmHandle; } diff --git a/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java index 2ff7ab299..7d6c2b41c 100644 --- a/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/egl/gbm/ScreenDriver.java @@ -31,6 +31,9 @@ import com.jogamp.nativewindow.DefaultGraphicsScreen; import com.jogamp.nativewindow.util.Rectangle; import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.MonitorMode; + +import jogamp.nativewindow.drm.DRMUtil; +import jogamp.nativewindow.drm.DrmMode; import jogamp.newt.MonitorModeProps; import jogamp.newt.ScreenImpl; @@ -45,26 +48,40 @@ public class ScreenDriver extends ScreenImpl { @Override protected void createNativeImpl() { aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); - initNative( DisplayDriver.getDrmHandle() ); + drmMode = DrmMode.create(DRMUtil.getDrmFd(), true /* preferNativeMode */); + if( DEBUG ) { + drmMode.print(System.err); + } } @Override - protected void closeNativeImpl() { } + protected void closeNativeImpl() { + drmMode.destroy(); + drmMode = null; + } @Override protected int validateScreenIndex(final int idx) { - return 0; // only one screen available + // FIXME add multi-monitor support + /** + if( 0 <= idx && idx < drmMode.count ) { + return idx; + } */ + return 0; } @Override protected void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) { + // FIXME add multi-monitor multi-mode support + final int scridx = 0; // getIndex(); + int[] props = new int[ MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL ]; int i = 0; props[i++] = MonitorModeProps.NUM_MONITOR_MODE_PROPERTIES_ALL; - props[i++] = cachedWidth; // width - props[i++] = cachedHeight; // height + props[i++] = drmMode.getModes()[scridx].getHdisplay(); + props[i++] = drmMode.getModes()[scridx].getVdisplay(); props[i++] = ScreenImpl.default_sm_bpp; // FIXME - props[i++] = cachedVRrefresh * 100; + props[i++] = drmMode.getModes()[scridx].getVrefresh() * 100; props[i++] = 0; // flags props[i++] = 0; // mode_idx props[i++] = 0; // rotation @@ -76,45 +93,40 @@ public class ScreenDriver extends ScreenImpl { props[i++] = 0; // crt_idx props[i++] = 0; // is-clone props[i++] = 1; // is-primary - props[i++] = ScreenImpl.default_sm_widthmm; // FIXME - props[i++] = ScreenImpl.default_sm_heightmm; // FIXME + props[i++] = drmMode.getConnectors()[scridx].getMmWidth(); + props[i++] = drmMode.getConnectors()[scridx].getMmHeight(); props[i++] = 0; // rotated viewport x pixel-units props[i++] = 0; // rotated viewport y pixel-units - props[i++] = cachedWidth; // rotated viewport width pixel-units - props[i++] = cachedHeight; // rotated viewport height pixel-units + props[i++] = drmMode.getModes()[scridx].getHdisplay(); // rotated viewport width pixel-units + props[i++] = drmMode.getModes()[scridx].getVdisplay(); // rotated viewport height pixel-units props[i++] = 0; // rotated viewport x window-units props[i++] = 0; // rotated viewport y window-units - props[i++] = cachedWidth; // rotated viewport width window-units - props[i++] = cachedHeight; // rotated viewport height window-units + props[i++] = drmMode.getModes()[scridx].getHdisplay(); // rotated viewport width window-units + props[i++] = drmMode.getModes()[scridx].getVdisplay(); // rotated viewport height window-units MonitorModeProps.streamInMonitorDevice(cache, this, currentMode, null, cache.monitorModes, props, 0, null); } @Override protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) { + // FIXME add multi-monitor multi-mode support return monitor.getSupportedModes().get(0); } @Override protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) { + // FIXME add multi-monitor multi-mode support return false; } @Override protected void calcVirtualScreenOriginAndSize(final Rectangle viewport, final Rectangle viewportInWindowUnits) { - viewport.set(0, 0, cachedWidth, cachedHeight); + // FIXME add multi-monitor support + final int scridx = 0; // getIndex(); + viewport.set(0, 0, drmMode.getModes()[scridx].getHdisplay(), drmMode.getModes()[scridx].getVdisplay()); viewportInWindowUnits.set(viewport); } - /** Called from {@link #initNative(long)}. */ - protected void notifyScreenMode(final int width, final int height, final int vrefresh) { - cachedWidth = width; // write to static field intended - cachedHeight = height; // write to static field intended - cachedVRrefresh = vrefresh; - } - - private static int cachedWidth = 0; - private static int cachedHeight = 0; - private static int cachedVRrefresh = 0; + /* pp */ DrmMode drmMode; protected static native boolean initIDs(); protected native void initNative(long drmHandle); diff --git a/src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java index 8517a132f..7253fac52 100644 --- a/src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java @@ -27,17 +27,27 @@ */ package jogamp.newt.driver.egl.gbm; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.AbstractGraphicsScreen; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.nativewindow.util.Point; import com.jogamp.nativewindow.util.Rectangle; import com.jogamp.nativewindow.util.RectangleImmutable; +import com.jogamp.newt.Display; import com.jogamp.opengl.GLCapabilitiesChooser; import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLException; import com.jogamp.opengl.egl.EGL; +import jogamp.nativewindow.drm.DRMLib; +import jogamp.nativewindow.drm.DRMUtil; +import jogamp.nativewindow.drm.DrmMode; +import jogamp.nativewindow.drm.drmModeModeInfo; import jogamp.newt.WindowImpl; import jogamp.newt.driver.linux.LinuxEventDeviceTracker; import jogamp.newt.driver.linux.LinuxMouseTracker; @@ -120,21 +130,66 @@ public class WindowDriver extends WindowImpl { } } + /** + * Align given rectangle to given screen bounds. + * + * @param screen + * @param rect the {@link RectangleImmutable} in pixel units + * @param definePosSize if {@code true} issue {@link #definePosition(int, int)} and {@link #defineSize(int, int)} + * if either has changed. + * @return If position or size has been aligned a new {@link RectangleImmutable} instance w/ clamped values + * will be returned, otherwise the given {@code rect} is returned. + */ + private RectangleImmutable alignRect2Screen(final ScreenDriver screen, final RectangleImmutable rect, final boolean definePosSize) { + int x = rect.getX(); + int y = rect.getY(); + int w = rect.getWidth(); + int h = rect.getHeight(); + final int s_w = screen.getWidth(); + final int s_h = screen.getHeight(); + boolean modPos = false; + boolean modSize = false; + if( 0 != x ) { + x = 0; + modPos = true; + } + if( 0 != y ) { + y = 0; + modPos = true; + } + if( s_w != w ) { + w = s_w; + modSize = true; + } + if( s_h != h ) { + h = s_h; + modSize = true; + } + if( modPos || modSize ) { + if( definePosSize ) { + if( modPos ) { + definePosition(x, y); + } + if( modSize ) { + defineSize(w, h); + } + } + return new Rectangle(x, y, w, h); + } else { + return rect; + } + } + @Override protected boolean canCreateNativeImpl() { // clamp if required incl. redefinition of position and size - clampRect((ScreenDriver) getScreen(), new Rectangle(getX(), getY(), getWidth(), getHeight()), true); - return true; // default: always able to be created - } + // clampRect((ScreenDriver) getScreen(), new Rectangle(getX(), getY(), getWidth(), getHeight()), true); - 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) ); + // Turns out DRM / GBM can only handle full screen size FB and crtc-modesetting (?) + alignRect2Screen((ScreenDriver) getScreen(), new Rectangle(getX(), getY(), getWidth(), getHeight()), true); + + return true; // default: always able to be created } - /** [31:0] x:R:G:B 8:8:8:8 little endian */ - static final int GBM_FORMAT_XRGB8888 = fourcc_code('X', 'R', '2', '4'); - /** [31:0] A:R:G:B 8:8:8:8 little endian */ - static final int GBM_FORMAT_ARGB8888 = fourcc_code('A', 'R', '2', '4'); @Override protected void createNativeImpl() { @@ -148,7 +203,12 @@ public class WindowDriver extends WindowImpl { // Create own screen/device resource instance allowing independent ownership, // while still utilizing shared EGL resources. final AbstractGraphicsScreen aScreen = screen.getGraphicsScreen(); - final int nativeVisualID = capsRequested.isBackgroundOpaque() ? GBM_FORMAT_XRGB8888 : GBM_FORMAT_ARGB8888; + final int nativeVisualID = capsRequested.isBackgroundOpaque() ? DRMUtil.GBM_FORMAT_XRGB8888 : DRMUtil.GBM_FORMAT_ARGB8888; + + final boolean ctDesktopGL = false; + if( !EGL.eglBindAPI( ctDesktopGL ? EGL.EGL_OPENGL_API : EGL.EGL_OPENGL_ES_API) ) { + throw new GLException("Caught: eglBindAPI to "+(ctDesktopGL ? "ES" : "GL")+" failed , error "+toHexString(EGL.eglGetError())); + } final EGLGraphicsConfiguration eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( (GLCapabilitiesImmutable)capsRequested, (GLCapabilitiesImmutable)capsRequested, (GLCapabilitiesChooser)capabilitiesChooser, @@ -157,8 +217,8 @@ public class WindowDriver extends WindowImpl { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } setGraphicsConfiguration(eglConfig); - final long nativeWindowHandle = CreateWindow0(DisplayDriver.getDrmHandle(), display.getGBMHandle(), - getX(), getY(), getWidth(), getHeight(), nativeVisualID); + final long nativeWindowHandle = DRMLib.gbm_surface_create(display.getGBMHandle(), getWidth(), getHeight(), nativeVisualID, + DRMLib.GBM_BO_USE_SCANOUT | DRMLib.GBM_BO_USE_RENDERING); if (nativeWindowHandle == 0) { throw new NativeWindowException("Error creating egl window: "+eglConfig); } @@ -174,15 +234,7 @@ public class WindowDriver extends WindowImpl { throw new NativeWindowException("Creation of eglSurface failed: "+eglConfig+", windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", error "+toHexString(EGL.eglGetError())); } - if(false) { - /** - if(!EGL.eglSwapBuffers(display.getHandle(), eglSurface)) { - throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); - } */ - lastBO = FirstSwapSurface0(DisplayDriver.getDrmHandle(), nativeWindowHandle, display.getHandle(), eglSurface); - } else { - lastBO = 0; - } + lastBO = 0; if( null != linuxEventDeviceTracker ) { addWindowListener(linuxEventDeviceTracker); @@ -196,8 +248,7 @@ public class WindowDriver extends WindowImpl { @Override protected void closeNativeImpl() { - final DisplayDriver display = (DisplayDriver) getScreen().getDisplay(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) getGraphicsConfiguration().getScreen().getDevice(); + final Display display = getScreen().getDisplay(); if( null != linuxMouseTracker ) { removeWindowListener(linuxMouseTracker); @@ -209,7 +260,7 @@ public class WindowDriver extends WindowImpl { lastBO = 0; if(0 != eglSurface) { try { - if (!EGL.eglDestroySurface(eglDevice.getHandle(), eglSurface)) { + if (!EGL.eglDestroySurface(display.getHandle(), eglSurface)) { throw new GLException("Error destroying window surface (eglDestroySurface)"); } } catch (final Throwable t) { @@ -219,11 +270,9 @@ public class WindowDriver extends WindowImpl { } } if( 0 != windowHandleClose ) { - CloseWindow0(display.getGBMHandle(), windowHandleClose); + DRMLib.gbm_surface_destroy(windowHandleClose); windowHandleClose = 0; } - - eglDevice.close(); } @Override @@ -233,21 +282,21 @@ public class WindowDriver extends WindowImpl { @Override public boolean surfaceSwap() { - final DisplayDriver display = (DisplayDriver) getScreen().getDisplay(); + final ScreenDriver screen = (ScreenDriver) getScreen(); + final DisplayDriver display = (DisplayDriver) screen.getDisplay(); final long nativeWindowHandle = getWindowHandle(); + final DrmMode d = screen.drmMode; + if(!EGL.eglSwapBuffers(display.getHandle(), eglSurface)) { + throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); + } if( 0 == lastBO ) { - /** if(!EGL.eglSwapBuffers(display.getHandle(), eglSurface)) { - throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); - } */ - lastBO = FirstSwapSurface0(DisplayDriver.getDrmHandle(), nativeWindowHandle, display.getHandle(), eglSurface); + lastBO = FirstSwapSurface(d.drmFd, d.getCrtcIDs()[0], getX(), getY(), d.getConnectors()[0].getConnector_id(), + d.getModes()[0], nativeWindowHandle); + } else { + lastBO = NextSwapSurface(d.drmFd, d.getCrtcIDs()[0], getX(), getY(), d.getConnectors()[0].getConnector_id(), + d.getModes()[0], nativeWindowHandle, lastBO); } - - /**if(!EGL.eglSwapBuffers(display.getHandle(), eglSurface)) { - throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); - } */ - lastBO = NextSwapSurface0(DisplayDriver.getDrmHandle(), nativeWindowHandle, lastBO, display.getHandle(), eglSurface); - System.exit(1); return true; // eglSwapBuffers done! } @@ -273,11 +322,11 @@ public class WindowDriver extends WindowImpl { @Override protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { - final RectangleImmutable rect = clampRect((ScreenDriver) getScreen(), new Rectangle(x, y, width, height), false); + // final RectangleImmutable rect = clampRect((ScreenDriver) getScreen(), new Rectangle(x, y, width, height), false); // reconfigure0 will issue position/size changed events if required - reconfigure0(getWindowHandle(), rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), flags); + // reconfigure0(getWindowHandle(), rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), flags); - return true; + return false; } @Override @@ -295,9 +344,29 @@ public class WindowDriver extends WindowImpl { private long lastBO; protected static native boolean initIDs(); - private native long CreateWindow0(long drmHandle, long gbmHandle, int x, int y, int width, int height, int nativeVisualID); - private native void CloseWindow0(long gbmDisplay, long eglWindowHandle); - private native void reconfigure0(long eglWindowHandle, int x, int y, int width, int height, int flags); - private native long FirstSwapSurface0(long drmHandle, long gbmSurface, long eglDisplay, long eglSurface); - private native long NextSwapSurface0(long drmHandle, long gbmSurface, long lastBO, long eglDisplay, long eglSurface); + // private native void reconfigure0(long eglWindowHandle, int x, int y, int width, int height, int flags); + + private long FirstSwapSurface(final int drmFd, final int crtc_id, final int x, final int y, final int connector_id, final drmModeModeInfo drmMode, final long gbmSurface) { + final ByteBuffer bb = drmMode.getBuffer(); + if(!Buffers.isDirect(bb)) { + throw new IllegalArgumentException("drmMode's buffer is not direct (NIO)"); + } + return FirstSwapSurface0(drmFd, crtc_id, x, y, connector_id, + bb, Buffers.getDirectBufferByteOffset(bb), + gbmSurface); + } + private native long FirstSwapSurface0(int drmFd, int crtc_id, int x, int y, int connector_id, Object mode, int mode_byte_offset, + long gbmSurface); + + private long NextSwapSurface(final int drmFd, final int crtc_id, final int x, final int y, final int connector_id, final drmModeModeInfo drmMode, final long gbmSurface, final long lastBO) { + final ByteBuffer bb = drmMode.getBuffer(); + if(!Buffers.isDirect(bb)) { + throw new IllegalArgumentException("drmMode's buffer is not direct (NIO)"); + } + return NextSwapSurface0(drmFd, crtc_id, x, y, connector_id, + bb, Buffers.getDirectBufferByteOffset(bb), + gbmSurface, lastBO); + } + private native long NextSwapSurface0(int drmFd, int crtc_id, int x, int y, int connector_id, Object mode, int mode_byte_offset, + long gbmSurface, long lastBO); } |