diff options
author | Sven Gothel <[email protected]> | 2019-12-07 08:33:48 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2019-12-07 08:33:48 +0100 |
commit | 6f750711fbcdf746451995e71165bbd119694269 (patch) | |
tree | c6f24d7d497650bce021a74f16851492ae1c813c | |
parent | b992423477ea1a76fb28946e28959a3feea97680 (diff) |
Bug 1156: DRM/GBM NEWT: Clarify drmModeSetCrtc(..)'s x/y parameter and earmark spanning across monitors
drmModeSetCrtc(..)'s x/y parameter are the surface's offset to be scanned out from one CRT!
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java | 163 | ||||
-rw-r--r-- | src/newt/native/drm_gbm_legacy.c | 81 |
2 files changed, 84 insertions, 160 deletions
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 ce1ffc1da..6d9940b95 100644 --- a/src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/egl/gbm/WindowDriver.java @@ -33,8 +33,6 @@ import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.AbstractGraphicsScreen; import com.jogamp.nativewindow.NativeWindowException; 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.newt.event.MouseEvent; import com.jogamp.opengl.GLCapabilitiesChooser; @@ -70,95 +68,24 @@ public class WindowDriver extends WindowImpl { windowHandleClose = 0; } - /** - * Clamp 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 clamped a new {@link RectangleImmutable} instance w/ clamped values - * will be returned, otherwise the given {@code rect} is returned. - */ - private RectangleImmutable clampRect(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(); + private void zeroPosition(final ScreenDriver screen, int x, int y) { boolean modPos = false; - boolean modSize = false; - if( 0 > x ) { + if( 0 != x ) { x = 0; modPos = true; } - if( 0 > y ) { + if( 0 != y ) { y = 0; modPos = true; } - if( s_w < x + w ) { - if( 0 < x ) { - x = 0; - modPos = true; - } - if( s_w < w ) { - w = s_w; - modSize = true; - } - } - if( s_h < y + h ) { - if( 0 < y ) { - y = 0; - modPos = 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; + if( modPos ) { + definePosition(x, y); } } - - /** - * 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(); + private void adjustSize(final ScreenDriver screen, int w, int h) { 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; @@ -167,29 +94,15 @@ public class WindowDriver extends WindowImpl { 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; + if( modSize ) { + defineSize(w, h); } } @Override protected boolean canCreateNativeImpl() { - // clamp if required incl. redefinition of position and size - // clampRect((ScreenDriver) getScreen(), new Rectangle(getX(), getY(), getWidth(), getHeight()), true); - - // Turns out DRM / GBM can only handle full screen size FB and crtc-modesetting (?) - alignRect2Screen((ScreenDriver) getScreen(), new Rectangle(getX(), getY(), getWidth(), getHeight()), true); - + zeroPosition((ScreenDriver) getScreen(), getX(), getY()); + adjustSize((ScreenDriver) getScreen(), getWidth(), getHeight()); return true; // default: always able to be created } @@ -292,15 +205,19 @@ public class WindowDriver extends WindowImpl { final GLContext ctx = GLContext.getCurrent(); final int swapInterval = ctx.getSwapInterval(); - ctx.getGL().glFinish(); // FIXME: Poor man's SYNC: glFenceSync () with glWaitSync() (remove later!) + ctx.getGL().glFinish(); // Poor man's SYNC: glFenceSync () with glWaitSync() (remove later!) if(!EGL.eglSwapBuffers(display.getHandle(), eglSurface)) { throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); } if( 0 == lastBO ) { - lastBO = FirstSwapSurface(d.drmFd, d.getCrtcIDs()[0], getX(), getY(), d.getConnectors()[0].getConnector_id(), - d.getModes()[0], nativeWindowHandle, swapInterval); + // FIXME: Support spanning across multiple CRTC (surface tiling) + final int surfaceOffsetX = 0; + final int surfaceOffsetY = 0; + lastBO = FirstSwapSurface(d.drmFd, d.getCrtcIDs()[0], surfaceOffsetX, surfaceOffsetY, + d.getConnectors()[0].getConnector_id(), + d.getModes()[0], nativeWindowHandle); } else { - lastBO = NextSwapSurface(d.drmFd, d.getCrtcIDs()[0], getX(), getY(), d.getConnectors()[0].getConnector_id(), + lastBO = NextSwapSurface(d.drmFd, d.getCrtcIDs()[0], d.getConnectors()[0].getConnector_id(), d.getModes()[0], nativeWindowHandle, lastBO, swapInterval); } return true; // eglSwapBuffers done! @@ -382,33 +299,59 @@ public class WindowDriver extends WindowImpl { protected static native boolean initIDs(); // 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, + /** + * First surface swap, actually initial surface/crtc setup. + * <p> + * {@code surfaceOffsetX} and {@code surfaceOffsetY} explained here + * <https://lists.freedesktop.org/archives/dri-devel/2014-February/053826.html>, + * useful to span surface across multiple monitors. + * </p> + * @param drmFd + * @param crtc_id the crtc to map to + * @param surfaceOffsetX the x-offset of the surface, which could span cross multiple crtc + * @param surfaceOffsetY the x-offset of the surface, which could span cross multiple crtc + * @param connector_id + * @param drmMode + * @param gbmSurface the surface to set on the crtc_id + * @return + */ + private long FirstSwapSurface(final int drmFd, final int crtc_id, final int surfaceOffsetX, final int surfaceOffsetY, final int connector_id, final drmModeModeInfo drmMode, - final long gbmSurface, final int swapInterval) { + 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, + return FirstSwapSurface0(drmFd, crtc_id, surfaceOffsetX, surfaceOffsetY, connector_id, bb, Buffers.getDirectBufferByteOffset(bb), - gbmSurface, swapInterval); + gbmSurface); } - private native long FirstSwapSurface0(int drmFd, int crtc_id, int x, int y, + private native long FirstSwapSurface0(int drmFd, int crtc_id, int surfaceOffsetX, int surfaceOffsetY, int connector_id, Object mode, int mode_byte_offset, - long gbmSurface, int swapInterval); + long gbmSurface); - private long NextSwapSurface(final int drmFd, final int crtc_id, final int x, final int y, + /** + * @param drmFd + * @param crtc_id the crtc to swap + * @param connector_id + * @param drmMode + * @param gbmSurface the surface to swap on the given crtc_id + * @param lastBO + * @param swapInterval the desired swap interval. Zero implies no vsync, otherwise vsync. + * @return + */ + private long NextSwapSurface(final int drmFd, final int crtc_id, final int connector_id, final drmModeModeInfo drmMode, final long gbmSurface, final long lastBO, final int swapInterval) { 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, + return NextSwapSurface0(drmFd, crtc_id, connector_id, bb, Buffers.getDirectBufferByteOffset(bb), gbmSurface, lastBO, swapInterval); } - private native long NextSwapSurface0(int drmFd, int crtc_id, int x, int y, + private native long NextSwapSurface0(int drmFd, int crtc_id, int connector_id, Object mode, int mode_byte_offset, long gbmSurface, long lastBO, int swapInterval); } diff --git a/src/newt/native/drm_gbm_legacy.c b/src/newt/native/drm_gbm_legacy.c index cec3297a8..9c4e19dc3 100644 --- a/src/newt/native/drm_gbm_legacy.c +++ b/src/newt/native/drm_gbm_legacy.c @@ -43,7 +43,6 @@ gbm_bo_get_offset(struct gbm_bo *bo, int plane); typedef struct { struct gbm_bo *bo; uint32_t fb_id; - uint32_t x, y; } DRM_FB; static void page_flip_handler(int fd, unsigned int frame, @@ -180,11 +179,12 @@ static DRM_FB * drm_fb_get_from_bo(int drmFd, struct gbm_bo *bo) } JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_FirstSwapSurface0 - (JNIEnv *env, jobject obj, jint drmFd, jint jcrtc_id, jint jx, jint jy, - jint jconnector_id, jobject jmode, jint jmode_byte_offset, - jlong jgbmSurface, jint swapInterval) + (JNIEnv *env, jobject obj, jint drmFd, jint jcrtc_id, jint jsurfaceOffsetX, jint jsurfaceOffsetY, + jint jconnector_id, jobject jmode, jint jmode_byte_offset, jlong jgbmSurface) { - uint32_t crtc_id = (uint32_t)jcrtc_id; + const uint32_t crtc_id = (uint32_t)jcrtc_id; + const uint32_t surfaceOffsetX = (uint32_t)jsurfaceOffsetX; + const uint32_t surfaceOffsetY = (uint32_t)jsurfaceOffsetY; uint32_t connector_id = (uint32_t)jconnector_id; drmModeModeInfo *drmMode = NULL; struct gbm_surface *gbmSurface = (struct gbm_surface *) (intptr_t) jgbmSurface; @@ -202,23 +202,34 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_FirstSwapSu ERR_PRINT("Failed to get a new framebuffer BO (0)\n"); return 0; } - fb->x = (uint32_t)jx; - fb->y = (uint32_t)jy; /** * Set Mode * * Fails with x/y != 0: -28 No space left on device * drmModeSetCrtc.0 failed to set mode: fd 26, crtc_id 0x27, fb_id 0x54, pos 10/10, conn_id 0x4d, curMode 1920x1080: -28 No space left on device + * + * See https://lists.freedesktop.org/archives/dri-devel/2014-February/053826.html: + * + * - The X,Y in drmModeSetCrtc does in fact specify the "source" offset into + * your framebuffer (not the destination on the CRTC) which is what I was looking for. + * + * - We were able to allocate both a Dumb buffer, and a GBM buffer the size of + * 6 1920x1200 monitors in a 1x6 configuration, so basically we didn't have + * any memory issues with a single buffer that big. + * + * - drmModeSetCrtc worked with both Dumb and GBM buffers, and we didn't have + * to do anything special on our end, so it clearly is handling the tiling + * issues behind the scenes (woot). */ - ret = drmModeSetCrtc(drmFd, crtc_id, fb->fb_id, fb->x, fb->y, + ret = drmModeSetCrtc(drmFd, crtc_id, fb->fb_id, surfaceOffsetX, surfaceOffsetY, &connector_id, 1, drmMode); if (ret) { - ERR_PRINT("drmModeSetCrtc.0 failed to set mode: fd %d, crtc_id 0x%x, fb_id 0x%x, pos %d/%d, conn_id 0x%x, curMode %s: %d %s\n", - drmFd, crtc_id, fb->fb_id, jx, jy, connector_id, drmMode->name, ret, strerror(errno)); + ERR_PRINT("drmModeSetCrtc.0 failed to set mode: fd %d, crtc_id 0x%x, fb_id 0x%x (offset %d/%d), conn_id 0x%x, curMode %s: %d %s\n", + drmFd, crtc_id, fb->fb_id, surfaceOffsetX, surfaceOffsetY, connector_id, drmMode->name, ret, strerror(errno)); return 0; } - DBG_PRINT( "EGL_GBM.Window FirstSwapSurface0 swapInterval %d, nextBO %p, fd %d, crtc_id 0x%x, fb_id 0x%x, pos %d/%d, conn_id 0x%x, curMode %s\n", - swapInterval, nextBO, drmFd, crtc_id, fb->fb_id, jx, jy, connector_id, drmMode->name); + DBG_PRINT( "EGL_GBM.Window FirstSwapSurface0 nextBO %p, fd %d, crtc_id 0x%x, fb_id 0x%x (offset %d/%d), conn_id 0x%x, curMode %s\n", + nextBO, drmFd, crtc_id, fb->fb_id, surfaceOffsetX, surfaceOffsetY, connector_id, drmMode->name); return (jlong) (intptr_t) nextBO; } @@ -227,17 +238,16 @@ static int nextSwapVerboseOnce = 1; #endif JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_NextSwapSurface0 - (JNIEnv *env, jobject obj, jint drmFd, jint jcrtc_id, jint jx, jint jy, + (JNIEnv *env, jobject obj, jint drmFd, jint jcrtc_id, jint jconnector_id, jobject jmode, jint jmode_byte_offset, jlong jgbmSurface, jlong jlastBO, jint swapInterval) { - uint32_t crtc_id = (uint32_t)jcrtc_id; - uint32_t x = (uint32_t)jx; - uint32_t y = (uint32_t)jy; - uint32_t connector_id = (uint32_t)jconnector_id; + const uint32_t crtc_id = (uint32_t)jcrtc_id; + const uint32_t connector_id = (uint32_t)jconnector_id; drmModeModeInfo *drmMode = NULL; struct gbm_surface *gbmSurface = (struct gbm_surface *) (intptr_t) jgbmSurface; - struct gbm_bo *lastBO = (struct gbm_bo*) (intptr_t) jlastBO, *nextBO = NULL; + struct gbm_bo *lastBO = (struct gbm_bo*) (intptr_t) jlastBO; + struct gbm_bo *nextBO = NULL; DRM_FB *fbNext = NULL; int ret, waiting_for_flip = 1; fd_set fds; @@ -252,30 +262,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_NextSwapSur ERR_PRINT("Failed to get a new framebuffer BO (1)\n"); return 0; } -#if 0 - if( fbNext->x != x || fbNext->y != y ) { - // position changed, hard drmModeSetCrtc(..) w/o vsync - fbNext->x = x; - fbNext->y = y; - - /** - * Set Mode - * - * Fails with x/y != 0: -28 No space left on device - * drmModeSetCrtc.0 failed to set mode: fd 26, crtc_id 0x27, fb_id 0x54, pos 10/10, conn_id 0x4d, curMode 1920x1080: -28 No space left on device - */ - ret = drmModeSetCrtc(drmFd, crtc_id, fbNext->fb_id, fbNext->x, fbNext->y, - &connector_id, 1, drmMode); - - if (ret) { - ERR_PRINT("drmModeSetCrtc.1 failed to set mode: fd %d, crtc_id 0x%x, fb_id 0x%x, pos %d/%d, conn_id 0x%x, curMode %s: %d %s\n", - drmFd, crtc_id, fbNext->fb_id, jx, jy, connector_id, drmMode->name, ret, strerror(errno)); - return 0; - } - } else -#endif if( 0 != swapInterval) { - // same position, use vsync + // https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-vsync.c#L614 ret = drmModePageFlip(drmFd, crtc_id, fbNext->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip); if (ret) { @@ -286,9 +274,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_NextSwapSur while (waiting_for_flip) { FD_ZERO(&fds); -#if 0 - FD_SET(0, &fds); // STDIN_FILENO: We don't want to listen to -#endif FD_SET(drmFd, &fds); ret = select(drmFd + 1, &fds, NULL, NULL, NULL); @@ -298,10 +283,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_NextSwapSur } else if (ret == 0) { ERR_PRINT("drm.select: select timeout!\n"); return -1; -#if 0 - } else if (FD_ISSET(0, &fds)) { - DBG_PRINT("drm.select: stdin carriage return pressed!\n"); -#endif } drmHandleEvent(drmFd, &drm_event_ctx); } @@ -315,8 +296,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_egl_gbm_WindowDriver_NextSwapSur #ifdef VERBOSE_ON if( nextSwapVerboseOnce ) { nextSwapVerboseOnce = 0; - DBG_PRINT( "EGL_GBM.Window NextSwapSurface0 swapInterval %d, bo %p -> %p, fd %d, crtc_id 0x%x, fb_id 0x%x, pos %d/%d, conn_id 0x%x, curMode %s\n", - swapInterval, lastBO, nextBO, drmFd, crtc_id, fbNext->fb_id, jx, jy, connector_id, drmMode->name); + DBG_PRINT( "EGL_GBM.Window NextSwapSurface0 swapInterval %d, bo %p -> %p, fd %d, crtc_id 0x%x, fb_id 0x%x, conn_id 0x%x, curMode %s\n", + swapInterval, lastBO, nextBO, drmFd, crtc_id, fbNext->fb_id, connector_id, drmMode->name); } #endif return (jlong) (intptr_t) nextBO; |