From fd06292d4a208cbd613f4bdce7cae12e075e70ec Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 5 Jul 2012 14:32:00 +0200 Subject: NativeWindow/Newt X11ErrorHandler enhancement / unification - don't throw exceptions. Handles also XAWT BadMatch X_SetInputFocus. X11ErrorHandler code now dumps proper information about the opcode and error message and the running Java thread. Having propery "nativewindow.debug.X11Util.XErrorStackDump" or "nativewindow.debug=all' set, a stack trace is dumped. Since the X11ErrorHandler may catch an XAWT error: BadMatch X_SetInputFocus, we cannot throw an exception and better keep running. --- src/nativewindow/native/x11/Xmisc.c | 208 ++++++++++++++++++------------------ src/nativewindow/native/x11/Xmisc.h | 44 ++++++++ 2 files changed, 147 insertions(+), 105 deletions(-) create mode 100644 src/nativewindow/native/x11/Xmisc.h (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 439d9b334..5cbf5c04a 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -26,15 +26,19 @@ * or implied, of JogAmp Community. */ +#include "NativewindowCommon.h" +#include "Xmisc.h" +#include "jogamp_nativewindow_x11_X11Lib.h" + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(args...) fprintf(stderr, args); +#else + #define DBG_PRINT(args...) +#endif + -#include -#include -#include -#include -#include -#include -#include -#include /* Linux headers don't work properly */ #define __USE_GNU #include @@ -80,17 +84,6 @@ Bool XF86VidModeSetGammaRamp( #define RTLD_DEFAULT NULL #endif -#include "NativewindowCommon.h" -#include "jogamp_nativewindow_x11_X11Lib.h" - -// #define VERBOSE_ON 1 - -#ifdef VERBOSE_ON - #define DBG_PRINT(args...) fprintf(stderr, args); -#else - #define DBG_PRINT(args...) -#endif - static const char * const ClazzNameBuffers = "com/jogamp/common/nio/Buffers"; static const char * const ClazzNameBuffersStaticCstrName = "copyByteBuffer"; static const char * const ClazzNameBuffersStaticCstrSignature = "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"; @@ -98,6 +91,9 @@ static const char * const ClazzNameByteBuffer = "java/nio/ByteBuffer"; static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; static const char * const ClazzAnyCstrName = ""; static const char * const ClazzNamePointCstrSignature = "(II)V"; +static jclass X11UtilClazz = NULL; +static jmethodID getCurrentThreadNameID = NULL; +static jmethodID dumpStackID = NULL; static jclass clazzBuffers = NULL; static jmethodID cstrBuffers = NULL; static jclass clazzByteBuffer = NULL; @@ -109,6 +105,15 @@ static void _initClazzAccess(JNIEnv *env) { if(!NativewindowCommon_init(env)) return; + getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;"); + if(NULL==getCurrentThreadNameID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName"); + } + dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V"); + if(NULL==dumpStackID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack"); + } + c = (*env)->FindClass(env, ClazzNameBuffers); if(NULL==c) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); @@ -162,66 +167,71 @@ static void setupJVMVars(JNIEnv * env) { } static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerBlocked = 0 ; static int errorHandlerQuiet = 0 ; +static int errorHandlerDebug = 0 ; +static int errorHandlerThrowException = 0; static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { if(!errorHandlerQuiet) { - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; - const char * errStr = strerror(errno); + const char * errnoStr = strerror(errno); + char threadName[80]; + char errCodeStr[80]; + char reqCodeStr[80]; - fprintf(stderr, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr); - fflush(stderr); + int shallBeDetached = 0; + JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; - if( JNI_EDETACHED == envRes ) { - // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "Nativewindow X11 Error: can't attach thread: %d\n", envRes); - return 0; + (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); + XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); + XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); + + fprintf(stderr, "Info: Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, + e->request_code, e->minor_code, reqCodeStr); + + if( errorHandlerDebug ) { + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + } + + if(errorHandlerThrowException) { + if(NULL != jniEnv) { + NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, + e->request_code, e->minor_code, reqCodeStr); + } else { + fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); + #if 0 + if(NULL!=origErrorHandler) { + origErrorHandler(dpy, e); + } + #endif } - curEnv = newEnv; - } else if( JNI_OK != envRes ) { - // oops .. - fprintf(stderr, "Nativewindow X11 Error: can't GetEnv: %d\n", envRes); - return 0; } - NativewindowCommon_throwNewRuntimeException(curEnv, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s", - dpy, e->error_code, errStr); + fflush(stderr); - if( NULL != newEnv ) { - // detached attached thread + if (NULL != jniEnv && shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } } -#if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } -#endif - return 0; } -static void x11ErrorHandlerEnable(Display *dpy, int onoff, JNIEnv * env) { - if(errorHandlerBlocked) return; - +void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { + errorHandlerQuiet = quiet; if(onoff) { if(NULL==origErrorHandler) { setupJVMVars(env); - if(NULL!=dpy) { + origErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(sync && NULL!=dpy) { XSync(dpy, False); } - origErrorHandler = XSetErrorHandler(x11ErrorHandler); } } else { if(NULL!=origErrorHandler) { - if(NULL!=dpy) { + if(sync && NULL!=dpy) { XSync(dpy, False); } XSetErrorHandler(origErrorHandler); @@ -230,46 +240,27 @@ static void x11ErrorHandlerEnable(Display *dpy, int onoff, JNIEnv * env) { } } -static void x11ErrorHandlerEnableBlocking(JNIEnv * env, int onoff, int quiet) { - errorHandlerBlocked = 0 ; - x11ErrorHandlerEnable(NULL, onoff, env); - errorHandlerBlocked = onoff ; - errorHandlerQuiet = quiet; -} - - static XIOErrorHandler origIOErrorHandler = NULL; static int x11IOErrorHandler(Display *dpy) { - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; const char * dpyName = XDisplayName(NULL); - const char * errStr = strerror(errno); + const char * errnoStr = strerror(errno); + char threadName[80]; + int shallBeDetached = 0; + JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errStr); + (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; - if( JNI_EDETACHED == envRes ) { - // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "Nativewindow X11 IOError: can't attach thread: %d\n", envRes); - return; - } - curEnv = newEnv; - } else if( JNI_OK != envRes ) { - // oops .. - fprintf(stderr, "Nativewindow X11 IOError: can't GetEnv: %d\n", envRes); - return; - } + fprintf(stderr, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s\n", threadName, dpy, dpyName, errnoStr); + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); - NativewindowCommon_FatalError(curEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errStr); + if (NULL != jniEnv) { + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); - if( NULL != newEnv ) { - // detached attached thread - (*jvmHandle)->DetachCurrentThread(jvmHandle); + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } if(NULL!=origIOErrorHandler) { origIOErrorHandler(dpy); @@ -293,22 +284,31 @@ static int _initialized=0; static jboolean _xinitThreadsOK=JNI_FALSE; JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass _unused, jboolean firstUIActionOnProcess) { +Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboolean firstUIActionOnProcess, jboolean debug) { if(0==_initialized) { + if(debug) { + errorHandlerDebug = 1; + } + X11UtilClazz = (jclass)(*env)->NewGlobalRef(env, clazz); if( JNI_TRUE == firstUIActionOnProcess ) { if( 0 == XInitThreads() ) { fprintf(stderr, "Warning: XInitThreads() failed\n"); } else { _xinitThreadsOK=JNI_TRUE; - DBG_PRINT( "X11: XInitThreads() called for concurrent Thread support\n"); + if(debug) { + fprintf(stderr, "X11: XInitThreads() called for concurrent Thread support\n"); + } } - } else { - DBG_PRINT( "X11: XInitThreads() _not_ called for concurrent Thread support\n"); + } else if(debug) { + fprintf(stderr, "X11: XInitThreads() _not_ called for concurrent Thread support\n"); } _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); _initialized=1; + if(JNI_TRUE == debug) { + fprintf(stderr, "Info: NativeWindow native init passed\n"); + } } return _xinitThreadsOK; } @@ -320,7 +320,7 @@ Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _unused, jboolean onoff, jboolean quiet) { - x11ErrorHandlerEnableBlocking(env, ( JNI_TRUE == onoff ) ? 1 : 0, ( JNI_TRUE == quiet ) ? 1 : 0); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, no sync */); } /* Java->C glue code: @@ -345,9 +345,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja if (arg3 != NULL) { _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); } - x11ErrorHandlerEnable((Display *) (intptr_t) arg0, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - x11ErrorHandlerEnable((Display *) (intptr_t) arg0, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -368,9 +368,9 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - x11ErrorHandlerEnable((Display *) (intptr_t) display, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); r = (jlong) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - x11ErrorHandlerEnable((Display *) (intptr_t) display, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); return r; } @@ -411,9 +411,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - x11ErrorHandlerEnable((Display *) (intptr_t) display, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - x11ErrorHandlerEnable(NULL, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); return _res; } @@ -451,7 +451,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow return 0; } - x11ErrorHandlerEnable(dpy, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); @@ -471,7 +471,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -511,13 +511,11 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow visual, attrMask, &xswa); - XSync(dpy, False); XSelectInput(dpy, window, 0); // no events - XSync(dpy, False); - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -541,11 +539,11 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow return; } - x11ErrorHandlerEnable(dpy, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); } /* @@ -569,11 +567,11 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio if( 0 == jdest_win ) { dest_win = root; } if( 0 == jsrc_win ) { src_win = root; } - x11ErrorHandlerEnable(dpy, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); diff --git a/src/nativewindow/native/x11/Xmisc.h b/src/nativewindow/native/x11/Xmisc.h new file mode 100644 index 000000000..a44da950d --- /dev/null +++ b/src/nativewindow/native/x11/Xmisc.h @@ -0,0 +1,44 @@ +/** + * Copyright 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: + * + * 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. + */ + +#ifndef Xmisc_h +#define Xmisc_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); + +#endif /* Xmisc_h */ -- cgit v1.2.3 From 627a27581688e0b12300370c751e3823b1afe44b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 6 Jul 2012 01:58:09 +0200 Subject: C code: remove warnings --- .../native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c | 6 +++--- src/nativewindow/native/x11/Xmisc.c | 8 ++++---- src/newt/native/X11Display.c | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c b/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c index 647de15ef..7fb64dade 100644 --- a/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c +++ b/src/jogl/native/libav/jogamp_opengl_util_av_impl_FFMPEGMediaPlayer.c @@ -572,7 +572,7 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_readNex (JNIEnv *env, jobject instance, jlong ptr, jlong jProcAddrGLTexSubImage2D, jint texTarget, jint texFmt, jint texType) { FFMPEGToolBasicAV_t *pAV = (FFMPEGToolBasicAV_t *)((void *)((intptr_t)ptr)); - PFNGLTEXSUBIMAGE2DPROC procAddrGLTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) jProcAddrGLTexSubImage2D; + PFNGLTEXSUBIMAGE2DPROC procAddrGLTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) (intptr_t)jProcAddrGLTexSubImage2D; jint res = 0; // 1 - audio, 2 - video AVPacket packet; @@ -694,10 +694,10 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_FFMPEGMediaPlayer_seek0 if(pos1 < pos0) { flags |= AVSEEK_FLAG_BACKWARD; } - fprintf(stderr, "SEEK: pre : u %d, p %d -> u %d, p %d\n", pos0, pts0, pos1, pts1); + fprintf(stderr, "SEEK: pre : u %ld, p %ld -> u %ld, p %ld\n", pos0, pts0, pos1, pts1); sp_av_seek_frame(pAV->pFormatCtx, pAV->vid, pts1, flags); pAV->vPTS = pAV->pVFrame->pkt_pts * my_av_q2i32(1000, pAV->pVStream->time_base); - fprintf(stderr, "SEEK: post : u %d, p %d\n", pAV->vPTS, pAV->pVFrame->pkt_pts); + fprintf(stderr, "SEEK: post : u %ld, p %ld\n", pAV->vPTS, pAV->pVFrame->pkt_pts); return pAV->vPTS; } diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 5cbf5c04a..21771c9aa 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -188,8 +188,8 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); fprintf(stderr, "Info: Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, - e->request_code, e->minor_code, reqCodeStr); + threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + (int)e->request_code, (int)e->minor_code, reqCodeStr); if( errorHandlerDebug ) { (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); @@ -198,8 +198,8 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) if(errorHandlerThrowException) { if(NULL != jniEnv) { NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, - e->request_code, e->minor_code, reqCodeStr); + threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + (int)e->request_code, (int)e->minor_code, reqCodeStr); } else { fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); #if 0 diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 5e2dc7c61..ce7d9a0e1 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -84,8 +84,8 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); fprintf(stderr, "Info: Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, - e->request_code, e->minor_code, reqCodeStr); + threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + (int)e->request_code, (int)e->minor_code, reqCodeStr); if( errorHandlerDebug ) { (*jniEnv)->CallStaticVoidMethod(jniEnv, X11NewtWindowClazz, dumpStackID); @@ -94,8 +94,8 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) if(errorHandlerThrowException) { if(NULL != jniEnv) { NewtCommon_throwNewRuntimeException(jniEnv, "Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, - e->request_code, e->minor_code, reqCodeStr); + threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + (int)e->request_code, (int)e->minor_code, reqCodeStr); } else { fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); #if 0 -- cgit v1.2.3 From 00bef95008b02cc71e166da122884402e9381f44 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 24 Jul 2012 00:14:02 +0200 Subject: Fix GraphicsConfigurationFactory: Map factory to device-type _and_ capabilities-type; Add a pre-set nativeVisualID to chooseGraphicsConfiguration(..) Map factory to device-type _and_ capabilities-type: - Allows using different GraphicsConfigurationFactory implementations for different capabilities-types. Previous impl. failed to use an OpenGL agnostic CapabilitiesImmutable for 'chooseGraphicsConfiguration(..)' since only the GL aware factory was mapped. The latter failed since it expected a GLCapabilitiesImmutable. - The passed capabilities-type as well as device-type given at getFactory(..) is traversed top-to-down to find a most suitable factory: For-All devT := getTopDownDeviceTypes(deviceType) For-All capsT := getTopDownCapabilitiesTypes(capabilitiesType) f = factory.get(devT, capsT); if(f) { return f; } end end Add a pre-set nativeVisualID to chooseGraphicsConfiguration(..) - In situations where a native visualID is already chosen [by external means for example], but we still need to query a matching GraphicsConfiguration - we require to pass a non VisualIDHolder.VID_UNDEFINED nativeVisualID. We had a hack implemented before within some implementations and their static calls, however an agnostic mechanism is required to implement new NativeSurface/Window's platform agnostic. - X11GLXGraphicsConfigurationFactory: respect a pre-set xvisualID - X11GLXDrawableFactory.createProxySurfaceImpl(..) queries the given windowHandle's visualID and 'chooses' the configuration accordingly. If the visualID is undefined an exception is thrown, since window is invalid. These mechanics are implicit for Windows and OSX. Fix X11GLXGraphicsConfiguration.updateGraphicsConfiguration(): - Skip any action if a valid X11GLCapabilities is already chosen, i.e. w/ visualID. Otherwise choose a suitable configuration incl. visualID. The latter is quite impossible and invalid, since visualID must be defined at window creation time and the update method is issued with a valid window. X11 - Misc: - Added 'int jogamp.nativewindow.x11.X11Lib.GetVisualIDFromWindow(..)' - All returned visualID's are of type 'int' --- make/config/nativewindow/x11-CustomJavaCode.java | 4 +- .../javax/media/opengl/GLDrawableFactory.java | 3 +- .../classes/javax/media/opengl/awt/GLCanvas.java | 9 +- .../jogamp/opengl/GLDrawableFactoryImpl.java | 3 + .../opengl/egl/EGLGraphicsConfiguration.java | 6 +- .../egl/EGLGraphicsConfigurationFactory.java | 16 +- .../cgl/MacOSXCGLGraphicsConfigurationFactory.java | 4 +- .../MacOSXAWTCGLGraphicsConfigurationFactory.java | 8 +- .../WindowsWGLGraphicsConfigurationFactory.java | 4 +- .../WindowsAWTWGLGraphicsConfigurationFactory.java | 8 +- .../opengl/x11/glx/X11ExternalGLXContext.java | 5 +- .../opengl/x11/glx/X11GLXDrawableFactory.java | 15 +- .../x11/glx/X11GLXGraphicsConfiguration.java | 29 ++- .../glx/X11GLXGraphicsConfigurationFactory.java | 113 ++++++++--- .../nativewindow/awt/AWTGraphicsConfiguration.java | 4 +- .../jogamp/nativewindow/x11/X11GraphicsDevice.java | 2 +- .../jogamp/nativewindow/x11/X11GraphicsScreen.java | 2 +- .../nativewindow/GraphicsConfigurationFactory.java | 226 +++++++++++++++++---- .../DefaultGraphicsConfigurationFactoryImpl.java | 2 +- .../x11/X11GraphicsConfigurationFactory.java | 18 +- .../awt/X11AWTGraphicsConfigurationFactory.java | 16 +- src/nativewindow/native/x11/Xmisc.c | 30 ++- src/newt/classes/jogamp/newt/OffscreenWindow.java | 5 +- .../classes/jogamp/newt/driver/awt/AWTCanvas.java | 6 +- .../jogamp/newt/driver/broadcom/egl/Window.java | 5 +- .../jogamp/newt/driver/intel/gdl/Window.java | 4 +- .../classes/jogamp/newt/driver/kd/KDWindow.java | 5 +- .../jogamp/newt/driver/macosx/MacWindow.java | 5 +- .../jogamp/newt/driver/windows/WindowsWindow.java | 5 +- .../classes/jogamp/newt/driver/x11/X11Window.java | 4 +- 30 files changed, 422 insertions(+), 144 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/make/config/nativewindow/x11-CustomJavaCode.java b/make/config/nativewindow/x11-CustomJavaCode.java index 73439fcc7..56aec4725 100644 --- a/make/config/nativewindow/x11-CustomJavaCode.java +++ b/make/config/nativewindow/x11-CustomJavaCode.java @@ -24,7 +24,9 @@ /** Entry point to C language function: XVisualInfo * XGetVisualInfo(Display * , long, XVisualInfo * , int * ); */ private static native java.nio.ByteBuffer XGetVisualInfo1(long arg0, long arg1, java.nio.ByteBuffer arg2, Object arg3, int arg3_byte_offset); - public static native long DefaultVisualID(long display, int screen); + public static native int GetVisualIDFromWindow(long display, long window); + + public static native int DefaultVisualID(long display, int screen); public static native long CreateDummyWindow(long display, int screen_index, int visualID, int width, int height); public static native void DestroyDummyWindow(long display, long window); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java index 612a02f14..9a0d2cb99 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -434,7 +434,8 @@ public abstract class GLDrawableFactory { /** * Creates a proxy {@link NativeSurface} w/ defined surface handle, i.e. a {@link WrappedSurface} or {@link GDISurface} instance. *

- * It's {@link AbstractGraphicsConfiguration} is properly set according to the given {@link GLCapabilitiesImmutable}. + * It's {@link AbstractGraphicsConfiguration} is properly set according to the given + * windowHandle's native visualID if set or the given {@link GLCapabilitiesImmutable}. *

*

* Lifecycle (destruction) of the given surface handle shall be handled by the caller. diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 694a081b8..03fd78ac7 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -60,6 +60,7 @@ import java.util.ArrayList; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; @@ -1062,9 +1063,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { config = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, aScreen); + chooser, aScreen, VisualIDHolder.VID_UNDEFINED); } else { try { final ArrayList bucket = new ArrayList(1); @@ -1072,9 +1073,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void run() { AWTGraphicsConfiguration c = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, aScreen); + chooser, aScreen, VisualIDHolder.VID_UNDEFINED); bucket.add(c); } }); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 34bb8704a..f092288fb 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -381,6 +381,9 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { if(null == device) { throw new GLException("No shared device for requested: "+deviceReq); } + if(0 == windowHandle) { + throw new IllegalArgumentException("Null windowHandle"); + } device.lock(); try { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 73867fb40..716a6e6f1 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -42,6 +42,7 @@ import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.DefaultGLCapabilitiesChooser; @@ -96,9 +97,10 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple } void updateGraphicsConfiguration() { + CapabilitiesImmutable capsChosen = getChosenCapabilities(); EGLGraphicsConfiguration newConfig = (EGLGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(getScreen().getDevice()).chooseGraphicsConfiguration( - getChosenCapabilities(), getRequestedCapabilities(), chooser, getScreen()); + GraphicsConfigurationFactory.getFactory(getScreen().getDevice(), capsChosen).chooseGraphicsConfiguration( + capsChosen, getRequestedCapabilities(), chooser, getScreen(), VisualIDHolder.VID_UNDEFINED); if(null!=newConfig) { // FIXME: setScreen( ... ); setChosenCapabilities(newConfig.getChosenCapabilities()); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java index d79c351a0..0b21d2054 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java @@ -81,27 +81,27 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact // become the pre-selector for X11/.. to match the native visual id w/ EGL, if native ES is selected final String nwType = NativeWindowFactory.getNativeWindowType(false); if(NativeWindowFactory.TYPE_X11 == nwType) { - nativeGraphicsConfigurationFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, eglFactory); + nativeGraphicsConfigurationFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, GLCapabilitiesImmutable.class, eglFactory); } /* else if(NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false)) { nativeGraphicsConfigurationFactory = GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.windows.WindowsGraphicsDevice.class, eglFactory); } else if(NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false)) { } */ // become the selector for KD/EGL .. - kdeglGraphicsConfigurationFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.egl.EGLGraphicsDevice.class, eglFactory); + kdeglGraphicsConfigurationFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.egl.EGLGraphicsDevice.class, GLCapabilitiesImmutable.class, eglFactory); } static void unregisterFactory() { final String nwType = NativeWindowFactory.getNativeWindowType(false); if(NativeWindowFactory.TYPE_X11 == nwType) { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, nativeGraphicsConfigurationFactory); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, GLCapabilitiesImmutable.class, nativeGraphicsConfigurationFactory); } /* else if(NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false)) { GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.windows.WindowsGraphicsDevice.class, nativeGraphicsConfigurationFactory); } else if(NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false)) { } */ nativeGraphicsConfigurationFactory = null; - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.egl.EGLGraphicsDevice.class, kdeglGraphicsConfigurationFactory); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.egl.EGLGraphicsDevice.class, GLCapabilitiesImmutable.class, kdeglGraphicsConfigurationFactory); kdeglGraphicsConfigurationFactory = null; } @@ -110,7 +110,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl ( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { if (absScreen == null) { throw new IllegalArgumentException("This NativeWindowFactory accepts only AbstractGraphicsDevice objects"); } @@ -140,7 +140,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact cfg = chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable) capsChosen, (GLCapabilitiesImmutable) capsRequested, (GLCapabilitiesChooser) chooser, - absScreen, VisualIDHolder.VID_UNDEFINED, false); + absScreen, nativeVisualID, false); } else { // handle non native cases (X11, ..) if(null == nativeGraphicsConfigurationFactory) { @@ -154,7 +154,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact cfg = chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable) capsChosen, (GLCapabilitiesImmutable) capsRequested, (GLCapabilitiesChooser) chooser, - absScreen, VisualIDHolder.VID_UNDEFINED, false); + absScreen, nativeVisualID, false); if(null == cfg || VisualIDHolder.VID_UNDEFINED == cfg.getVisualID(VIDType.NATIVE)) { cfg = null; if(DEBUG) { @@ -167,7 +167,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact if(DEBUG) { System.err.println("EGLGraphicsConfigurationFactory.choose..: Delegate to "+nativeGraphicsConfigurationFactory.getClass().getSimpleName()); } - cfg = nativeGraphicsConfigurationFactory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, absScreen); + cfg = nativeGraphicsConfigurationFactory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, absScreen, nativeVisualID); } } return cfg; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java index 1a9070aef..f138e7557 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java @@ -50,14 +50,14 @@ import javax.media.opengl.GLCapabilitiesImmutable; public class MacOSXCGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { static void registerFactory() { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice.class, new MacOSXCGLGraphicsConfigurationFactory()); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice.class, GLCapabilitiesImmutable.class, new MacOSXCGLGraphicsConfigurationFactory()); } private MacOSXCGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, absScreen, false); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java index a6fa01bad..edf9b7c84 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java @@ -58,14 +58,14 @@ import jogamp.opengl.macosx.cgl.MacOSXCGLGraphicsConfiguration; public class MacOSXAWTCGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { public static void registerFactory() { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, new MacOSXAWTCGLGraphicsConfigurationFactory()); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, GLCapabilitiesImmutable.class, new MacOSXAWTCGLGraphicsConfigurationFactory()); } private MacOSXAWTCGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { GraphicsDevice device = null; if (absScreen != null && !(absScreen instanceof AWTGraphicsScreen)) { @@ -103,9 +103,9 @@ public class MacOSXAWTCGLGraphicsConfigurationFactory extends GLGraphicsConfigur GraphicsConfiguration gc = device.getDefaultConfiguration(); MacOSXCGLGraphicsConfiguration macConfig = (MacOSXCGLGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(macDevice).chooseGraphicsConfiguration(capsChosen, + GraphicsConfigurationFactory.getFactory(macDevice, capsChosen).chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, macScreen); + chooser, macScreen, nativeVisualID); if (macConfig == null) { throw new GLException("Unable to choose a GraphicsConfiguration: "+capsChosen+",\n\t"+chooser+"\n\t"+macScreen); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index 943c7fec4..00ed91bb4 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -69,13 +69,13 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat static VisualIDHolder.VIDComparator PfdIDComparator = new VisualIDHolder.VIDComparator(VisualIDHolder.VIDType.WIN32_PFD); static void registerFactory() { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.windows.WindowsGraphicsDevice.class, new WindowsWGLGraphicsConfigurationFactory()); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.windows.WindowsGraphicsDevice.class, GLCapabilitiesImmutable.class, new WindowsWGLGraphicsConfigurationFactory()); } private WindowsWGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { if (! (capsChosen instanceof GLCapabilitiesImmutable) ) { throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - chosen"); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java index bd64b58a4..3b2ff133a 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java @@ -63,14 +63,14 @@ import javax.media.opengl.GLDrawableFactory; public class WindowsAWTWGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { public static void registerFactory() { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, new WindowsAWTWGLGraphicsConfigurationFactory()); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, GLCapabilitiesImmutable.class, new WindowsAWTWGLGraphicsConfigurationFactory()); } private WindowsAWTWGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { GraphicsDevice device = null; if (absScreen != null && !(absScreen instanceof AWTGraphicsScreen)) { @@ -105,11 +105,11 @@ public class WindowsAWTWGLGraphicsConfigurationFactory extends GLGraphicsConfigu WindowsGraphicsDevice winDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); DefaultGraphicsScreen winScreen = new DefaultGraphicsScreen(winDevice, awtScreen.getIndex()); - GraphicsConfigurationFactory configFactory = GraphicsConfigurationFactory.getFactory(winDevice); + GraphicsConfigurationFactory configFactory = GraphicsConfigurationFactory.getFactory(winDevice, capsChosen); WindowsWGLGraphicsConfiguration winConfig = (WindowsWGLGraphicsConfiguration) configFactory.chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, winScreen); + chooser, winScreen, nativeVisualID); if (winConfig == null) { throw new GLException("Unable to choose a GraphicsConfiguration: "+capsChosen+",\n\t"+chooser+"\n\t"+winScreen); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java index b847363e0..1f3edbd8a 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java @@ -41,6 +41,7 @@ package jogamp.opengl.x11.glx; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; @@ -94,9 +95,9 @@ public class X11ExternalGLXContext extends X11GLXContext { // of 0, which doesn't work in a subsequent call to glXChooseFBConfig; if this happens, // create and use a default config (this has been observed when running on CentOS 5.5 inside // of VMWare Server 2.0 with the Mesa 6.5.1 drivers) - if( X11GLXGraphicsConfiguration.GLXFBConfigIDValid(display, x11Screen.getIndex(), val[0]) ) { + if( VisualIDHolder.VID_UNDEFINED == val[0] || !X11GLXGraphicsConfiguration.GLXFBConfigIDValid(display, x11Screen.getIndex(), val[0]) ) { GLCapabilities glcapsDefault = new GLCapabilities(GLProfile.getDefault()); - cfg = X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(glcapsDefault, glcapsDefault, null, x11Screen); + cfg = X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(glcapsDefault, glcapsDefault, null, x11Screen, VisualIDHolder.VID_UNDEFINED); if(DEBUG) { System.err.println("X11ExternalGLXContext invalid FBCONFIG_ID "+val[0]+", using default cfg: " + cfg); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 8ffbf3951..b2e74f9d4 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -50,6 +50,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; +import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; @@ -514,7 +515,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { device = (X11GraphicsDevice)deviceReq; } final X11GraphicsScreen screen = new X11GraphicsScreen(device, 0); - final X11GLXGraphicsConfiguration config = X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen); + final X11GLXGraphicsConfiguration config = X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED); if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } @@ -582,7 +583,17 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), NativeWindowFactory.getNullToolkitLock(), true); final X11GraphicsScreen screen = new X11GraphicsScreen(device, screenIdx); - final X11GLXGraphicsConfiguration cfg = X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen); + final int xvisualID = X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); + if(VisualIDHolder.VID_UNDEFINED == xvisualID) { + throw new GLException("Undefined VisualID of window 0x"+Long.toHexString(windowHandle)+", window probably invalid"); + } + if(DEBUG) { + System.err.println("X11GLXDrawableFactory.createProxySurfaceImpl 0x"+Long.toHexString(windowHandle)+": visualID 0x"+Integer.toHexString(xvisualID)); + } + final X11GLXGraphicsConfiguration cfg = X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, xvisualID); + if(DEBUG) { + System.err.println("X11GLXDrawableFactory.createProxySurfaceImpl 0x"+Long.toHexString(windowHandle)+": "+cfg); + } return new WrappedSurface(cfg, windowHandle, 0, 0, upstream); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java index 95b1cc457..b458fffe1 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java @@ -37,7 +37,9 @@ import java.util.ArrayList; import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.DefaultGLCapabilitiesChooser; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; @@ -102,16 +104,25 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem } void updateGraphicsConfiguration() { - X11GLXGraphicsConfiguration newConfig = (X11GLXGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(getScreen().getDevice()).chooseGraphicsConfiguration( - getChosenCapabilities(), getRequestedCapabilities(), chooser, getScreen()); - if(null!=newConfig) { - // FIXME: setScreen( ... ); - setXVisualInfo(newConfig.getXVisualInfo()); - setChosenCapabilities(newConfig.getChosenCapabilities()); - if(DEBUG) { - System.err.println("updateGraphicsConfiguration: "+this); + final CapabilitiesImmutable aChosenCaps = getChosenCapabilities(); + if( !(aChosenCaps instanceof X11GLCapabilities) || VisualIDHolder.VID_UNDEFINED == aChosenCaps.getVisualID(VIDType.X11_XVISUAL) ) { + // This case is actually quite impossible, since on X11 the visualID and hence GraphicsConfiguration + // must be determined _before_ window creation! + final X11GLXGraphicsConfiguration newConfig = (X11GLXGraphicsConfiguration) + GraphicsConfigurationFactory.getFactory(getScreen().getDevice(), aChosenCaps).chooseGraphicsConfiguration( + aChosenCaps, getRequestedCapabilities(), chooser, getScreen(), VisualIDHolder.VID_UNDEFINED); + if(null!=newConfig) { + // FIXME: setScreen( ... ); + setXVisualInfo(newConfig.getXVisualInfo()); + setChosenCapabilities(newConfig.getChosenCapabilities()); + if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.updateGraphicsConfiguration updated:"+this); + } + } else { + throw new GLException("No native VisualID pre-chosen and update failed: "+this); } + } else if (DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.updateGraphicsConfiguration kept:"+this); } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java index 331401c06..234b06bdb 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java @@ -40,6 +40,7 @@ import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.VisualIDHolder; +import javax.media.nativewindow.VisualIDHolder.VIDType; import javax.media.opengl.DefaultGLCapabilitiesChooser; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; @@ -74,20 +75,24 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF static GraphicsConfigurationFactory fallbackX11GraphicsConfigurationFactory = null; static void registerFactory() { final GraphicsConfigurationFactory newFactory = new X11GLXGraphicsConfigurationFactory(); - final GraphicsConfigurationFactory oldFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, newFactory); + final GraphicsConfigurationFactory oldFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, GLCapabilitiesImmutable.class, newFactory); if(oldFactory == newFactory) { throw new InternalError("GraphicsConfigurationFactory lifecycle impl. error"); } - if(null == oldFactory) { - throw new InternalError("Missing fallback GraphicsConfigurationFactory"); + if(null != oldFactory) { + fallbackX11GraphicsConfigurationFactory = oldFactory; + } else { + fallbackX11GraphicsConfigurationFactory = GraphicsConfigurationFactory.getFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, CapabilitiesImmutable.class); + if( null == fallbackX11GraphicsConfigurationFactory ) { + throw new InternalError("Missing fallback GraphicsConfigurationFactory"); + } } - fallbackX11GraphicsConfigurationFactory = oldFactory; } private X11GLXGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { if (!(absScreen instanceof X11GraphicsScreen)) { throw new IllegalArgumentException("Only X11GraphicsScreen are allowed here"); } @@ -109,12 +114,12 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF if(DEBUG) { System.err.println("No GLX available, fallback to "+fallbackX11GraphicsConfigurationFactory.getClass().getSimpleName()+" for: "+absScreen); } - return fallbackX11GraphicsConfigurationFactory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, absScreen); + return fallbackX11GraphicsConfigurationFactory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, absScreen, VisualIDHolder.VID_UNDEFINED); } throw new InternalError("No GLX and no fallback GraphicsConfigurationFactory available for: "+absScreen); } return chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, - (GLCapabilitiesChooser)chooser, (X11GraphicsScreen)absScreen); + (GLCapabilitiesChooser)chooser, (X11GraphicsScreen)absScreen, nativeVisualID); } protected static List getAvailableCapabilities(X11GLXDrawableFactory factory, AbstractGraphicsDevice device) { @@ -199,7 +204,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF static X11GLXGraphicsConfiguration chooseGraphicsConfigurationStatic(GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, GLCapabilitiesChooser chooser, - X11GraphicsScreen x11Screen) { + X11GraphicsScreen x11Screen, int xvisualID) { if (x11Screen == null) { throw new IllegalArgumentException("AbstractGraphicsScreen is null"); } @@ -215,19 +220,19 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF X11GLXGraphicsConfiguration res = null; if( factory.isGLXVersionGreaterEqualOneThree(x11Device) ) { - res = chooseGraphicsConfigurationFBConfig(capsChosen, capsReq, chooser, x11Screen); + res = chooseGraphicsConfigurationFBConfig(capsChosen, capsReq, chooser, x11Screen, xvisualID); } if(null==res) { if(usePBuffer) { - throw new GLException("Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig for "+capsChosen); + throw new GLException("Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig for visualID "+toHexString(xvisualID)+", "+capsChosen); } - res = chooseGraphicsConfigurationXVisual(capsChosen, capsReq, chooser, x11Screen); + res = chooseGraphicsConfigurationXVisual(capsChosen, capsReq, chooser, x11Screen, xvisualID); } if(null==res) { - throw new GLException("Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig and XVisual for "+capsChosen); + throw new GLException("Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig and XVisual for visualID "+toHexString(xvisualID)+", "+x11Screen+", "+capsChosen); } if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationStatic("+x11Screen+","+capsChosen+"): "+res); + System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationStatic(visualID "+toHexString(xvisualID)+", "+x11Screen+","+capsChosen+"): "+res); } return res; } @@ -253,7 +258,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF private static X11GLXGraphicsConfiguration chooseGraphicsConfigurationFBConfig(GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, GLCapabilitiesChooser chooser, - X11GraphicsScreen x11Screen) { + X11GraphicsScreen x11Screen, int xvisualID) { int recommendedIndex = -1; PointerBuffer fbcfgsL = null; GLProfile glProfile = capsChosen.getGLProfile(); @@ -273,8 +278,11 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF int[] count = { -1 }; List availableCaps = new ArrayList(); final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, useFBO); - // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice - fbcfgsL = GLX.glXChooseFBConfig(display, screen, attribs, 0, count, 0); + // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice, + // skipped if xvisualID is given + if( VisualIDHolder.VID_UNDEFINED == xvisualID ) { + fbcfgsL = GLX.glXChooseFBConfig(display, screen, attribs, 0, count, 0); + } if (fbcfgsL != null && fbcfgsL.limit()>0) { for (int i = 0; i < fbcfgsL.limit(); i++) { if( !X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(availableCaps, glProfile, absDevice, fbcfgsL.get(i), winattrmask, isMultisampleAvailable) ) { @@ -317,6 +325,33 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } } } + + if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: got configs: "+availableCaps.size()); + for(int i=0; i chosenIndex ) { if (DEBUG) { @@ -333,7 +368,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF private static X11GLXGraphicsConfiguration chooseGraphicsConfigurationXVisual(GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, GLCapabilitiesChooser chooser, - X11GraphicsScreen x11Screen) { + X11GraphicsScreen x11Screen, int xvisualID) { if (chooser == null) { chooser = new DefaultGLCapabilitiesChooser(); } @@ -351,14 +386,18 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice); int[] attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, false, isMultisampleAvailable, display, screen); + XVisualInfo recommendedVis = null; // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice - XVisualInfo recommendedVis = GLX.glXChooseVisual(display, screen, attribs, 0); - if (DEBUG) { - System.err.print("glXChooseVisual recommended "); - if (recommendedVis == null) { - System.err.println("null visual"); - } else { - System.err.println("visual id " + toHexString(recommendedVis.getVisualid())); + // skipped if xvisualID is given + if( VisualIDHolder.VID_UNDEFINED == xvisualID ) { + recommendedVis = GLX.glXChooseVisual(display, screen, attribs, 0); + if (DEBUG) { + System.err.print("glXChooseVisual recommended "); + if (recommendedVis == null) { + System.err.println("null visual"); + } else { + System.err.println("visual id " + toHexString(recommendedVis.getVisualid())); + } } } @@ -384,6 +423,32 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } } + if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: got configs: "+availableCaps.size()); + for(int i=0; i chosenIndex ) { if (DEBUG) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java index 61d5e5c0d..2a152ff35 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java @@ -95,8 +95,8 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsRequested, gc); } - final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice); - final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, null, awtScreen); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice, capsChosen); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, null, awtScreen, VisualIDHolder.VID_UNDEFINED); if(config instanceof AWTGraphicsConfiguration) { return (AWTGraphicsConfiguration) config; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java index 7a98e3c25..5e4d6f41a 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java @@ -88,7 +88,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl // It still could be an AWT hold handle .. final long display = getHandle(); final int scrnIdx = X11Lib.DefaultScreen(display); - return (int) X11Lib.DefaultVisualID(display, scrnIdx); + return X11Lib.DefaultVisualID(display, scrnIdx); } @Override diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java index 014f4f688..5f3c220ca 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java @@ -58,7 +58,7 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl public int getVisualID() { // It still could be an AWT hold handle .. - return (int) X11Lib.DefaultVisualID(getDevice().getHandle(), getIndex()); + return X11Lib.DefaultVisualID(getDevice().getHandle(), getIndex()); } private static int fetchScreen(X11GraphicsDevice device, int screen) { diff --git a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index 2610f2cfa..c3fdc6798 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -36,9 +36,15 @@ package javax.media.nativewindow; import com.jogamp.common.util.ReflectionUtil; import jogamp.nativewindow.Debug; import jogamp.nativewindow.DefaultGraphicsConfigurationFactoryImpl; + +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Set; /** * Provides the mechanism by which the graphics configuration for a @@ -59,8 +65,43 @@ import java.util.Map; public abstract class GraphicsConfigurationFactory { protected static final boolean DEBUG; - private static Map, GraphicsConfigurationFactory> registeredFactories; - private static Class abstractGraphicsDeviceClass; + private static class DeviceCapsType { + public final Class deviceType; + public final Class capsType; + private final int hash32; + + public DeviceCapsType(Class deviceType, Class capsType) { + this.deviceType = deviceType; + this.capsType = capsType; + + // 31 * x == (x << 5) - x + int hash32 = 31 + deviceType.hashCode(); + hash32 = ((hash32 << 5) - hash32) + capsType.hashCode(); + this.hash32 = hash32; + } + + public final int hashCode() { + return hash32; + } + + public final boolean equals(Object obj) { + if(this == obj) { return true; } + if (obj instanceof DeviceCapsType) { + DeviceCapsType dct = (DeviceCapsType)obj; + return deviceType == dct.deviceType && capsType == dct.capsType; + } + return false; + } + + @Override + public final String toString() { + return "DeviceCapsType["+deviceType.getName()+", "+capsType.getName()+"]"; + } + + } + + private static final Map registeredFactories; + private static final DeviceCapsType defaultDeviceCapsType; static boolean initialized = false; static { @@ -69,7 +110,8 @@ public abstract class GraphicsConfigurationFactory { System.err.println(Thread.currentThread().getName()+" - Info: GraphicsConfigurationFactory."); // Thread.dumpStack(); } - abstractGraphicsDeviceClass = javax.media.nativewindow.AbstractGraphicsDevice.class; + registeredFactories = Collections.synchronizedMap(new HashMap()); + defaultDeviceCapsType = new DeviceCapsType(AbstractGraphicsDevice.class, CapabilitiesImmutable.class); } public static synchronized void initSingleton() { @@ -79,14 +121,13 @@ public abstract class GraphicsConfigurationFactory { if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.initSingleton()"); } - registeredFactories = Collections.synchronizedMap(new HashMap, GraphicsConfigurationFactory>()); // Register the default no-op factory for arbitrary // AbstractGraphicsDevice implementations, including // AWTGraphicsDevice instances -- the OpenGL binding will take // care of handling AWTGraphicsDevices on X11 platforms (as // well as X11GraphicsDevices in non-AWT situations) - registerFactory(abstractGraphicsDeviceClass, new DefaultGraphicsConfigurationFactoryImpl()); + registerFactory(defaultDeviceCapsType.deviceType, defaultDeviceCapsType.capsType, new DefaultGraphicsConfigurationFactoryImpl()); if (NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { try { @@ -112,7 +153,6 @@ public abstract class GraphicsConfigurationFactory { System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.shutdown()"); } registeredFactories.clear(); - registeredFactories = null; } } @@ -133,74 +173,175 @@ public abstract class GraphicsConfigurationFactory { protected GraphicsConfigurationFactory() { } - /** Returns the factory for use with the given type of - AbstractGraphicsDevice. */ - public static GraphicsConfigurationFactory getFactory(AbstractGraphicsDevice device) { + /** + * Returns the graphics configuration factory for use with the + * given device and capability. + * + * @see #getFactory(Class, Class) + */ + public static GraphicsConfigurationFactory getFactory(AbstractGraphicsDevice device, CapabilitiesImmutable caps) { if (device == null) { - return getFactory(AbstractGraphicsDevice.class); + throw new IllegalArgumentException("null device"); + } + if (caps == null) { + throw new IllegalArgumentException("null caps"); } - return getFactory(device.getClass()); + return getFactory(device.getClass(), caps.getClass()); } /** * Returns the graphics configuration factory for use with the - * given class, which must implement the {@link - * AbstractGraphicsDevice} interface. + * given device and capability class. + *

+ * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only. + *

+ * + *

+ * Pseudo code for finding a suitable factory is: + *

+        For-All devT := getTopDownDeviceTypes(deviceType)
+            For-All capsT := getTopDownCapabilitiesTypes(capabilitiesType)
+               f = factory.get(devT, capsT);
+               if(f) { return f; }
+            end
+        end
+     * 
+ *

* - * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice + * @param deviceType the minimum capabilities class type accepted, must implement or extend {@link AbstractGraphicsDevice} + * @param capabilitiesType the minimum capabilities class type accepted, must implement or extend {@link CapabilitiesImmutable} + * + * @throws IllegalArgumentException if the deviceType does not implement {@link AbstractGraphicsDevice} or + * capabilitiesType does not implement {@link CapabilitiesImmutable} */ - public static GraphicsConfigurationFactory getFactory(Class abstractGraphicsDeviceImplementor) + public static GraphicsConfigurationFactory getFactory(Class deviceType, Class capabilitiesType) throws IllegalArgumentException, NativeWindowException { - if (!(abstractGraphicsDeviceClass.isAssignableFrom(abstractGraphicsDeviceImplementor))) { + if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(deviceType))) { throw new IllegalArgumentException("Given class must implement AbstractGraphicsDevice"); } - - GraphicsConfigurationFactory factory = null; - Class clazz = abstractGraphicsDeviceImplementor; - while (clazz != null) { - factory = registeredFactories.get(clazz); - if (factory != null) { - if(DEBUG) { - System.err.println("GraphicsConfigurationFactory.getFactory() "+abstractGraphicsDeviceImplementor+" -> "+factory); + if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) { + throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable"); + } + if(DEBUG) { + Thread.dumpStack(); + System.err.println("GraphicsConfigurationFactory.getFactory: "+deviceType.getName()+", "+capabilitiesType.getName()); + dumpFactories(); + } + + final List> deviceTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.deviceType, deviceType, false); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() deviceTypes: " + deviceTypes); + } + final List> capabilitiesTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.capsType, capabilitiesType, true); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() capabilitiesTypes: " + capabilitiesTypes); + } + for(int j=0; j interfaceDevice = deviceTypes.get(j); + for(int i=0; i interfaceCaps = capabilitiesTypes.get(i); + final DeviceCapsType dct = new DeviceCapsType(interfaceDevice, interfaceCaps); + final GraphicsConfigurationFactory factory = registeredFactories.get(dct); + if (factory != null) { + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() found "+dct+" -> "+factory); + } + return factory; } - return factory; } - clazz = clazz.getSuperclass(); } // Return the default - factory = registeredFactories.get(abstractGraphicsDeviceClass); + final GraphicsConfigurationFactory factory = registeredFactories.get(defaultDeviceCapsType); if(DEBUG) { - System.err.println("GraphicsConfigurationFactory.getFactory() DEFAULT "+abstractGraphicsDeviceClass+" -> "+factory); + System.err.println("GraphicsConfigurationFactory.getFactory() DEFAULT "+defaultDeviceCapsType+" -> "+factory); } return factory; } + private static ArrayList> getAllAssignableClassesFrom(Class superClassOrInterface, Class fromClass, boolean interfacesOnly) { + // Using a todo list avoiding a recursive loop! + final ArrayList> inspectClasses = new ArrayList>(); + final ArrayList> resolvedInterfaces = new ArrayList>(); + inspectClasses.add(fromClass); + for(int j=0; j clazz = inspectClasses.get(j); + getAllAssignableClassesFrom(superClassOrInterface, clazz, interfacesOnly, resolvedInterfaces, inspectClasses); + } + return resolvedInterfaces; + } + private static void getAllAssignableClassesFrom(Class superClassOrInterface, Class fromClass, boolean interfacesOnly, List> resolvedInterfaces, List> inspectClasses) { + final ArrayList> types = new ArrayList>(); + if( superClassOrInterface.isAssignableFrom(fromClass) && !resolvedInterfaces.contains(fromClass)) { + if( !interfacesOnly || fromClass.isInterface() ) { + types.add(fromClass); + } + } + types.addAll(Arrays.asList(fromClass.getInterfaces())); + + for(int i=0; i iface = types.get(i); + if( superClassOrInterface.isAssignableFrom(iface) && !resolvedInterfaces.contains(iface) ) { + resolvedInterfaces.add(iface); + if( !superClassOrInterface.equals(iface) && !inspectClasses.contains(iface) ) { + inspectClasses.add(iface); // safe add to todo list, avoiding a recursive nature + } + } + } + final Class parentClass = fromClass.getSuperclass(); + if( null != parentClass && superClassOrInterface.isAssignableFrom(parentClass) && !inspectClasses.contains(parentClass) ) { + inspectClasses.add(parentClass); // safe add to todo list, avoiding a recursive nature + } + } + private static void dumpFactories() { + Set dcts = registeredFactories.keySet(); + int i=0; + for(Iterator iter = dcts.iterator(); iter.hasNext(); ) { + DeviceCapsType dct = iter.next(); + System.err.println("Factory #"+i+": "+dct+" -> "+registeredFactories.get(dct)); + i++; + } + } - /** Registers a GraphicsConfigurationFactory handling graphics - * device objects of the given class. This does not need to be - * called by end users, only implementors of new + /** + * Registers a GraphicsConfigurationFactory handling + * the given graphics device and capability class. + *

+ * This does not need to be called by end users, only implementors of new * GraphicsConfigurationFactory subclasses. - * + *

+ * + *

+ * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only. + *

+ * + *

See {@link #getFactory(Class, Class)} for a description of the find algorithm.

+ * + * @param deviceType the minimum capabilities class type accepted, must implement or extend interface {@link AbstractGraphicsDevice} + * @param capabilitiesType the minimum capabilities class type accepted, must extend interface {@link CapabilitiesImmutable} * @return the previous registered factory, or null if none * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice */ - protected static GraphicsConfigurationFactory registerFactory(Class abstractGraphicsDeviceImplementor, GraphicsConfigurationFactory factory) + protected static GraphicsConfigurationFactory registerFactory(Class abstractGraphicsDeviceImplementor, Class capabilitiesType, GraphicsConfigurationFactory factory) throws IllegalArgumentException { - if (!(abstractGraphicsDeviceClass.isAssignableFrom(abstractGraphicsDeviceImplementor))) { - throw new IllegalArgumentException("Given class must implement AbstractGraphicsDevice"); + if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(abstractGraphicsDeviceImplementor))) { + throw new IllegalArgumentException("Given device class must implement AbstractGraphicsDevice"); } + if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) { + throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable"); + } + final DeviceCapsType dct = new DeviceCapsType(abstractGraphicsDeviceImplementor, capabilitiesType); final GraphicsConfigurationFactory prevFactory; if(null == factory) { - prevFactory = registeredFactories.remove(abstractGraphicsDeviceImplementor); + prevFactory = registeredFactories.remove(dct); if(DEBUG) { - System.err.println("GraphicsConfigurationFactory.registerFactory() remove "+abstractGraphicsDeviceImplementor+ + System.err.println("GraphicsConfigurationFactory.registerFactory() remove "+dct+ ", deleting: "+prevFactory); } } else { - prevFactory = registeredFactories.put(abstractGraphicsDeviceImplementor, factory); + prevFactory = registeredFactories.put(dct, factory); if(DEBUG) { - System.err.println("GraphicsConfigurationFactory.registerFactory() put "+abstractGraphicsDeviceImplementor+" -> "+factory+ + System.err.println("GraphicsConfigurationFactory.registerFactory() put "+dct+" -> "+factory+ ", overridding: "+prevFactory); } } @@ -244,6 +385,7 @@ public abstract class GraphicsConfigurationFactory { * @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 @@ -258,7 +400,7 @@ public abstract class GraphicsConfigurationFactory { public final AbstractGraphicsConfiguration chooseGraphicsConfiguration(CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, - AbstractGraphicsScreen screen) + AbstractGraphicsScreen screen, int nativeVisualID) throws IllegalArgumentException, NativeWindowException { if(null==capsChosen) { throw new NativeWindowException("Chosen Capabilities are null"); @@ -275,7 +417,7 @@ public abstract class GraphicsConfigurationFactory { } device.lock(); try { - return chooseGraphicsConfigurationImpl(capsChosen, capsRequested, chooser, screen); + return chooseGraphicsConfigurationImpl(capsChosen, capsRequested, chooser, screen, nativeVisualID); } finally { device.unlock(); } @@ -283,7 +425,7 @@ public abstract class GraphicsConfigurationFactory { protected abstract AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl(CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen screen) + CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) throws IllegalArgumentException, NativeWindowException; } diff --git a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java index f34b740d4..52e9c8308 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java @@ -37,7 +37,7 @@ import javax.media.nativewindow.*; public class DefaultGraphicsConfigurationFactoryImpl extends GraphicsConfigurationFactory { protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) { + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) { return new DefaultGraphicsConfiguration(screen, capsChosen, capsRequested); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index 070f87216..b11dd1df1 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -39,33 +39,39 @@ import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.VisualIDHolder; import com.jogamp.nativewindow.x11.X11GraphicsConfiguration; import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { public static void registerFactory() { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, new X11GraphicsConfigurationFactory()); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, CapabilitiesImmutable.class, new X11GraphicsConfigurationFactory()); } private X11GraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) throws IllegalArgumentException, NativeWindowException { if(!(screen instanceof X11GraphicsScreen)) { throw new NativeWindowException("Only valid X11GraphicsScreen are allowed"); } - final X11Capabilities x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, capsChosen)); - AbstractGraphicsConfiguration res = new X11GraphicsConfiguration((X11GraphicsScreen)screen, x11CapsChosen, capsRequested, x11CapsChosen.getXVisualInfo()); + final X11Capabilities x11CapsChosen; + if(VisualIDHolder.VID_UNDEFINED == nativeVisualID) { + x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, capsChosen)); + } else { + x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, nativeVisualID)); + } + final AbstractGraphicsConfiguration res = new X11GraphicsConfiguration((X11GraphicsScreen)screen, x11CapsChosen, capsRequested, x11CapsChosen.getXVisualInfo()); if(DEBUG) { - System.err.println("X11GraphicsConfigurationFactory.chooseGraphicsConfigurationImpl("+screen+","+capsChosen+"): "+res); + System.err.println("X11GraphicsConfigurationFactory.chooseGraphicsConfigurationImpl(visualID 0x"+Integer.toHexString(nativeVisualID)+", "+screen+","+capsChosen+"): "+res); } return res; } - public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, long visualID) + public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, int visualID) { XVisualInfo xvi_temp = XVisualInfo.create(); xvi_temp.setVisualid(visualID); diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java index b6bf63d44..1de03e8be 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -61,14 +61,14 @@ import jogamp.nativewindow.x11.X11Util; public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory { public static void registerFactory() { - GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, new X11AWTGraphicsConfigurationFactory()); + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, CapabilitiesImmutable.class, new X11AWTGraphicsConfigurationFactory()); } private X11AWTGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { if (absScreen != null && !(absScreen instanceof AWTGraphicsScreen)) { throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects"); @@ -77,18 +77,18 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac absScreen = AWTGraphicsScreen.createDefault(); } - return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen); + return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen, nativeVisualID); } public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen) { + CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen, int nativeVisualID) { if(DEBUG) { System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen); } final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); - + final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); final long displayHandle; boolean owner = false; @@ -121,8 +121,8 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen); } - final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device); - AbstractGraphicsConfiguration aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device, capsChosen); + AbstractGraphicsConfiguration aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen, nativeVisualID); if (aConfig == null) { throw new NativeWindowException("Unable to choose a GraphicsConfiguration (1): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); } @@ -160,7 +160,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac // try again using an AWT Colormodel compatible configuration GraphicsConfiguration gc = device.getDefaultConfiguration(); capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsChosen, gc); - aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen, nativeVisualID); if (aConfig == null) { throw new NativeWindowException("Unable to choose a GraphicsConfiguration (2): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); } diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 21771c9aa..fcba8580c 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -362,14 +362,40 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja return jbyteCopy; } -JNIEXPORT jlong JNICALL +JNIEXPORT jint JNICALL +Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _unused, jlong display, jlong window) { + Display * dpy = (Display *)(intptr_t)display; + Window w = (Window) window; + XWindowAttributes xwa; + jlong r = 0; // undefinded + + if(NULL==dpy) { + NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); + return; + } + + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 1); + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, w, &xwa); + if(NULL != xwa.visual) { + r = (jint) XVisualIDFromVisual( xwa.visual ); + } else { + r = 0; + } + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + + return r; +} + + +JNIEXPORT jint JNICALL Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, jlong display, jint screen) { jlong r; if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); - r = (jlong) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); + r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); return r; } diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java index be543aba9..ba98ca3af 100644 --- a/src/newt/classes/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java @@ -40,6 +40,7 @@ import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; @@ -72,8 +73,8 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface { dummySurface.createNotify(); } } */ - final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aScreen.getDevice()).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, aScreen); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aScreen.getDevice(), capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, aScreen, VisualIDHolder.VID_UNDEFINED); if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java index 5a49dd57c..a7950048a 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java @@ -46,6 +46,7 @@ import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.VisualIDHolder; import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; @@ -53,6 +54,7 @@ import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; import com.jogamp.newt.Window; +@SuppressWarnings("serial") public class AWTCanvas extends Canvas { private GraphicsDevice device; private GraphicsConfiguration chosen; @@ -252,9 +254,9 @@ public class AWTCanvas extends Canvas { AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT): AWTGraphicsScreen.createDefault(); AWTGraphicsConfiguration config = (AWTGraphicsConfiguration) - GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, capsChosen.getClass()).chooseGraphicsConfiguration(capsChosen, capsRequested, - chooser, aScreen); + chooser, aScreen, VisualIDHolder.VID_UNDEFINED); if (config == null) { throw new NativeWindowException("Error: Couldn't fetch AWTGraphicsConfiguration"); } diff --git a/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java b/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java index ed1d0511a..223ad6484 100644 --- a/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java +++ b/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java @@ -37,6 +37,7 @@ package jogamp.newt.driver.broadcom.egl; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; import javax.media.opengl.GLCapabilitiesImmutable; @@ -57,8 +58,8 @@ public class Window extends jogamp.newt.WindowImpl { } // query a good configuration, however chose the final one by the native queried egl-cfg-id // after creation at {@link #windowCreated(int, int, int)}. - final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java index 09e0e3016..d5c75abd4 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java @@ -54,8 +54,8 @@ public class Window extends jogamp.newt.WindowImpl { final AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); final AbstractGraphicsDevice aDevice = getScreen().getDisplay().getGraphicsDevice(); - final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aDevice).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, aScreen); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aDevice, capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, aScreen, VisualIDHolder.VID_UNDEFINED); if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } diff --git a/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java b/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java index bb76d21ff..9f9d6948e 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java +++ b/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java @@ -37,6 +37,7 @@ package jogamp.newt.driver.kd; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.VisualIDHolder.VIDType; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; @@ -59,8 +60,8 @@ public class KDWindow extends WindowImpl { if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported (yet)"); } - final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java index fcca5c843..720d4ee4c 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java @@ -39,6 +39,7 @@ import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.MutableSurface; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; @@ -61,8 +62,8 @@ public class MacWindow extends WindowImpl implements MutableSurface, DriverClear @Override protected void createNativeImpl() { - final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java index 5e636d982..34d76a148 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java @@ -41,6 +41,7 @@ import jogamp.newt.WindowImpl; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; @@ -119,8 +120,8 @@ public class WindowsWindow extends WindowImpl { protected void createNativeImpl() { final WindowsScreen screen = (WindowsScreen) getScreen(); final WindowsDisplay display = (WindowsDisplay) screen.getDisplay(); - final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen()); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java index 9a5074c29..5501f5a3c 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java @@ -63,9 +63,9 @@ public class X11Window extends WindowImpl { protected void createNativeImpl() { final X11Screen screen = (X11Screen) getScreen(); final X11Display display = (X11Display) screen.getDisplay(); - final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice(), capsRequested); final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen()); + capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); if(DEBUG_IMPLEMENTATION) { System.err.println("X11Window.createNativeImpl() factory: "+factory+", chosen config: "+cfg); } -- cgit v1.2.3 From fbe331f013608eb31ff0d8675f4e4c9881c9c48b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 27 Sep 2012 17:33:39 +0200 Subject: Fix Bug 616: X11: Remove XInitThreads() dependency while cleaning up device locking, resulting in a native-lock-free impl. The X11 implementation details of NativeWindow and NEWT used the X11 implicit locking facility XLockDisplay/XUnlockDisplay, enabled via XInitThreads(). The latter useage is complicated within an unsure environment where the initialization point of JOGL is unknown, but XInitThreads() requires to be called once and before any other X11 calls. The solution is simple and thorough, replace native X11 locking w/ 'application level' locking. Following this pattern actually cleans up a pretty messy part of X11 NativeWindow and NEWT, since the generalization of platform independent locking simplifies code. Simply using our RecursiveLock also speeds up locking, since it doesn't require JNI calls down to X11 anymore. It allows us to get rid of X11ToolkitLock and X11JAWTToolkitLock. Using the RecursiveLock also allows us to remove the shortcut of explicitly createing a NullToolkitLocked device for 'private' display connections. All devices use proper locking as claimed in their toolkit util 'requiresToolkitLock()' in X11Util, OSXUtil, .. Further more a bug has been fixed of X11ErrorHandler usage, i.e. we need to keep our handler alive at all times due to async X11 messaging behavior. This allows to remove the redundant code in X11/NEWT. The AbstractGraphicsDevice lifecycle has been fixed as well, i.e. called when closing NEWT's Display for all driver implementations. On the NEWT side the Display's AbstractGraphicsDevice semantics has been clarified, i.e. it's usage for EDT and lifecycle operations. Hence the X11 Display 2nd device for rendering operations has been moved to X11 Window where it belongs - and the X11 Display's default device used for EDT/lifecycle-ops as it should be. This allows running X11/NEWT properly with the default usage, where the Display instance and hence the EDT thread is shared with many Screen and Window. Rendering using NEWT Window is decoupled from it's shared Display lock via it's own native X11 display. Lock free AbstractGraphicsDevice impl. (Windows, OSX, ..) don't require any attention in this regard since they use NullToolkitLock. Tests: ====== This implementation has been tested manually with Mesa3d (soft, Intel), ATI and Nvidia on X11, Windows and OSX w/o any regressions found in any unit test. Issues on ATI: ============== Only on ATI w/o a composite renderer the unit tests expose a driver or WM bug where XCB claims a lack of locking. Setting env. var 'LIBXCB_ALLOW_SLOPPY_LOCK=true' is one workaround if users refuse to enable compositing. We may investigate this issue in more detail later on. --- make/scripts/tests.sh | 50 ++++- .../classes/jogamp/opengl/egl/EGLDisplayUtil.java | 3 +- .../jogamp/opengl/x11/glx/X11GLXContext.java | 37 +--- .../opengl/x11/glx/X11GLXDrawableFactory.java | 13 +- .../jogamp/nativewindow/x11/X11GraphicsDevice.java | 2 +- .../jogamp/nativewindow/x11/X11GraphicsScreen.java | 2 +- .../media/nativewindow/AbstractGraphicsDevice.java | 2 +- .../media/nativewindow/DefaultGraphicsDevice.java | 3 +- .../media/nativewindow/NativeWindowFactory.java | 99 ++------- .../javax/media/nativewindow/ToolkitLock.java | 18 +- .../jogamp/nativewindow/NullToolkitLock.java | 9 + .../jogamp/nativewindow/ResourceToolkitLock.java | 74 +++++++ .../nativewindow/SharedResourceToolkitLock.java | 141 +++++++++++++ .../classes/jogamp/nativewindow/jawt/JAWTUtil.java | 3 + .../nativewindow/jawt/x11/X11JAWTToolkitLock.java | 76 ------- .../nativewindow/jawt/x11/X11JAWTWindow.java | 3 +- .../jogamp/nativewindow/x11/X11ToolkitLock.java | 70 ------ .../classes/jogamp/nativewindow/x11/X11Util.java | 119 ++++------- .../awt/X11AWTGraphicsConfigurationFactory.java | 7 +- src/nativewindow/native/x11/Xmisc.c | 38 ++-- src/newt/classes/com/jogamp/newt/Display.java | 35 ++- src/newt/classes/com/jogamp/newt/NewtFactory.java | 2 +- src/newt/classes/com/jogamp/newt/Screen.java | 2 +- src/newt/classes/jogamp/newt/DisplayImpl.java | 79 ++++--- src/newt/classes/jogamp/newt/ScreenImpl.java | 3 +- src/newt/classes/jogamp/newt/WindowImpl.java | 33 +-- .../jogamp/newt/driver/awt/DisplayDriver.java | 4 +- .../jogamp/newt/driver/bcm/egl/DisplayDriver.java | 2 + .../newt/driver/intel/gdl/DisplayDriver.java | 1 + .../jogamp/newt/driver/macosx/DisplayDriver.java | 4 +- .../jogamp/newt/driver/windows/DisplayDriver.java | 1 + .../jogamp/newt/driver/x11/DisplayDriver.java | 65 ++---- .../jogamp/newt/driver/x11/ScreenDriver.java | 31 ++- .../jogamp/newt/driver/x11/WindowDriver.java | 107 +++++++--- src/newt/native/X11Common.h | 1 - src/newt/native/X11Display.c | 91 -------- src/newt/native/X11Window.c | 10 - .../junit/jogl/acore/InitConcurrentBaseNEWT.java | 219 +++++++++++++++++++ .../junit/jogl/acore/TestInitConcurrent01NEWT.java | 78 +++++++ .../junit/jogl/acore/TestInitConcurrent02NEWT.java | 78 +++++++ .../junit/jogl/acore/TestInitConcurrentNEWT.java | 235 --------------------- 41 files changed, 964 insertions(+), 886 deletions(-) create mode 100644 src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java create mode 100644 src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java delete mode 100644 src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java delete mode 100644 src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent02NEWT.java delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java (limited to 'src/nativewindow/native/x11') diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 8a0a638ba..3dc983072 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -81,6 +81,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLDebugMessageHandler -Djogl.debug.TraceGL -Djogl.debug.DebugGL -Djogl.debug.GLSLCode -Djogl.debug.GLSLState" #D_ARGS="-Djogl.debug.GLDebugMessageHandler -Djogl.debug.DebugGL -Djogl.debug.TraceGL" #D_ARGS="-Djogamp.debug.NativeLibrary -Djogamp.debug.NativeLibrary.UseCurrentThreadLibLoader" + #D_ARGS="-Djogamp.debug.NativeLibrary" #D_ARGS="-Djogl.1thread=false -Djogl.debug.Threading" #D_ARGS="-Djogl.1thread=true -Djogl.debug.Threading" #D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.TraceGL -Djogl.debug.GLContext.TraceSwitch -Djogl.debug=all" @@ -100,7 +101,6 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile -Djogl.debug.GLDrawable" #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile" #D_ARGS="-Djogl.debug.GLProfile" - #D_ARGS="-Dnewt.debug.EDT -Dnativewindow.debug.ToolkitLock.TraceLock -Dnativewindow.debug.NativeWindow" #D_ARGS="-Dnativewindow.debug.NativeWindow" #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT" #D_ARGS="-Dnewt.debug.EDT -Dnewt.debug.Window -Djogl.debug.GLContext" @@ -109,6 +109,7 @@ function jrun() { #D_ARGS="-Dnativewindow.debug.X11Util -Dnativewindow.debug.X11Util.XSync" #D_ARGS="-Dnativewindow.debug.X11Util.XSync -Dnewt.debug.Window" #D_ARGS="-Djogl.debug.GLDrawable -Djogl.debug.GLContext" + #D_ARGS="-Dnativewindow.debug.NativeWindow -Dnativewindow.debug.X11Util" #D_ARGS="-Djogamp.common.utils.locks.Lock.timeout=3000 -Djogamp.debug.Lock -Djogl.debug.GLContext.TraceSwitch" #D_ARGS="-Djogamp.common.utils.locks.Lock.timeout=600000 -Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock" #D_ARGS="-Djogamp.common.utils.locks.Lock.timeout=600000 -Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock -Dnativewindow.debug.ToolkitLock.TraceLock" @@ -135,7 +136,9 @@ function jrun() { #D_ARGS="-Djogl.debug.Animator" #D_ARGS="-Dnativewindow.debug=all" #D_ARGS="-Djogl.debug.GLCanvas" - #D_ARGS="-Dnativewindow.debug.ToolkitLock.TraceLock" + #D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.X11Util.XSync" + #D_ARGS="-Dnativewindow.debug.X11Util.XSync" + #D_ARGS="-Dnativewindow.debug.ToolkitLock" #D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLCode -Djogl.debug.TraceGL" #D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLState" #D_ARGS="-Djogamp.debug.JNILibLoader -Djogamp.debug.TempJarCache -Djogamp.debug.JarUtil" @@ -187,6 +190,8 @@ function jrun() { #export LD_LIBRARY_PATH=/opt-linux-x86_64/mesa-7.8.1/lib64:$LD_LIBRARY_PATH #export LD_LIBRARY_PATH=/usr/lib/mesa:/usr/lib32/mesa:$LD_LIBRARY_PATH #export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/mesa:/usr/lib/i386-linux-gnu/mesa:$LD_LIBRARY_PATH + #export LD_LIBRARY_PATH=`pwd`/lib/external/mesa/x86_64-linux-gnu:$LD_LIBRARY_PATH + #export LD_LIBRARY_PATH=`pwd`/lib/external/mesa/x86_64-linux-gnu/gallium:$LD_LIBRARY_PATH echo echo "Test Start: $*" echo @@ -194,10 +199,10 @@ function jrun() { echo echo $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* #LIBGL_DRIVERS_PATH=/usr/lib/mesa:/usr/lib32/mesa \ - #gdb --args $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* #LIBGL_DEBUG=verbose INTEL_STRICT_CONFORMANCE=1 INTEL_DEBUG="buf bat" \ #LIBGL_DEBUG=verbose MESA_DEBUG=true INTEL_STRICT_CONFORMANCE=1 \ - #LIBGL_DEBUG=verbose MESA_DEBUG=true LIBGL_ALWAYS_SOFTWARE=true \ + #export LIBGL_DEBUG=verbose MESA_DEBUG=true LIBGL_ALWAYS_SOFTWARE=true + #gdb --args $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* echo echo "Test End: $*" @@ -239,7 +244,8 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrentNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent02NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextSurfaceLockNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT $* @@ -250,6 +256,38 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $* +# x11 no XinitThreads() specific tests (regressions, concurrent behavior) ! +# Deadlock: +# com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 - test01 +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $* +# com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT - testEachWithAnimatorSharedOffscreen +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $* +# +# XCB: +# +# com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT - testShaderState01PerformanceDouble +#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT $* +# com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT - testWindowParenting02ReparentTop2WinReparentRecreate +#testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT $* +# com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT - winHopFrame2FrameDirectHop +#testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $* + +#testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle02NEWT +#testnoawt com.jogamp.opengl.test.junit.newt.TestWindows01NEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent01NEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent02NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMix2DemosES2NEWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $* +#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteGLWindows01NEWT $* +#testswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTEclipseGLCanvas01GLn $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1DemoES2NEWT $* + + #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT $* @@ -322,7 +360,7 @@ function testawtswt() { #testawt com.jogamp.opengl.test.junit.jogl.awt.TestAWT02WindowClosing #testawt com.jogamp.opengl.test.junit.jogl.awt.text.TestAWTTextRendererUseVertexArrayBug464 #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT $* -testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $* +#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWTAnalyzeBug455 $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWTBug450 $* diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java index ce2e824f5..0a603ab8a 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java @@ -71,10 +71,9 @@ public class EGLDisplayUtil { Thread.dumpStack(); } if( eglDisplayCounter.size() > 0) { - EGLDisplayUtil.dumpOpenDisplayConnections(); + dumpOpenDisplayConnections(); } } - return eglDisplayCounter.size(); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index e1e25be67..bdccc1047 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -172,7 +172,6 @@ public abstract class X11GLXContext extends GLContextImpl { glXMakeContextCurrent(display, 0, 0, 0); GLX.glXDestroyContext(display, ctx); } - private static final int ctx_arb_attribs_idx_major = 0; private static final int ctx_arb_attribs_idx_minor = 2; private static final int ctx_arb_attribs_idx_flags = 6; @@ -228,14 +227,14 @@ public abstract class X11GLXContext extends GLContextImpl { X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); - long display = device.getHandle(); + final long display = device.getHandle(); try { // critical path, a remote display might not support this command, // hence we need to catch the X11 Error within this block. - X11Lib.XSync(display, false); + X11Util.setX11ErrorHandler(true, DEBUG ? false : true); // make sure X11 error handler is set ctx = _glXExt.glXCreateContextAttribsARB(display, config.getFBConfig(), share, direct, attribs); - X11Lib.XSync(display, false); + if(DEBUG) { X11Lib.XSync(display, false); } } catch (RuntimeException re) { if(DEBUG) { Throwable t = new Throwable(getThreadName()+": Info: X11GLXContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation"), re); @@ -263,16 +262,6 @@ public abstract class X11GLXContext extends GLContextImpl { @Override protected boolean createImpl(GLContextImpl shareWith) { - // covers the whole context creation loop incl createContextARBImpl and destroyContextARBImpl - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - return createImplRaw(shareWith); - } finally { - X11Util.setX11ErrorHandler(false, false); - } - } - - private boolean createImplRaw(GLContextImpl shareWith) { boolean direct = true; // try direct always isDirect = false; // fall back @@ -401,14 +390,9 @@ public abstract class X11GLXContext extends GLContextImpl { protected void makeCurrentImpl() throws GLException { long dpy = drawable.getNativeSurface().getDisplayHandle(); - if (GLX.glXGetCurrentContext() != contextHandle) { - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - if (!glXMakeContextCurrent(dpy, drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { - throw new GLException(getThreadName()+": Error making context current: "+this); - } - } finally { - X11Util.setX11ErrorHandler(false, false); + if (GLX.glXGetCurrentContext() != contextHandle) { + if (!glXMakeContextCurrent(dpy, drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { + throw new GLException(getThreadName()+": Error making context current: "+this); } } } @@ -416,13 +400,8 @@ public abstract class X11GLXContext extends GLContextImpl { @Override protected void releaseImpl() throws GLException { long display = drawable.getNativeSurface().getDisplayHandle(); - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - if (!glXMakeContextCurrent(display, 0, 0, 0)) { - throw new GLException(getThreadName()+": Error freeing OpenGL context"); - } - } finally { - X11Util.setX11ErrorHandler(false, false); + if (!glXMakeContextCurrent(display, 0, 0, 0)) { + throw new GLException(getThreadName()+": Error freeing OpenGL context"); } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index ca5cd424b..03c661565 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -47,7 +47,6 @@ import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeSurface; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.nativewindow.VisualIDHolder; @@ -230,11 +229,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { @Override public SharedResourceRunner.Resource createSharedResource(String connection) { - final X11GraphicsDevice sharedDevice = - new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, - true); // own non-shared display connection, w/ locking - // new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, - // NativeWindowFactory.getNullToolkitLock(), true); // own non-shared display connection, w/o locking + final X11GraphicsDevice sharedDevice = new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, true); sharedDevice.lock(); try { final X11GraphicsScreen sharedScreen = new X11GraphicsScreen(sharedDevice, sharedDevice.getDefaultScreen()); @@ -509,8 +504,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { final X11GraphicsDevice device; if(createNewDevice) { - // Null X11 locking, due to private non-shared Display handle - device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), NativeWindowFactory.getNullToolkitLock(), true); + // Null X11 resource locking, due to private non-shared Display handle + device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), true); } else { device = (X11GraphicsDevice)deviceReq; } @@ -531,7 +526,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { @Override protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { - final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), NativeWindowFactory.getNullToolkitLock(), true); + final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), true); final X11GraphicsScreen screen = new X11GraphicsScreen(device, screenIdx); final int xvisualID = X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); if(VisualIDHolder.VID_UNDEFINED == xvisualID) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java index 152384980..2e4099c1b 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java @@ -73,7 +73,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl /** * @param display the Display connection - * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking in NEWT + * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking w/ private connection * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long, ToolkitLock) */ public X11GraphicsDevice(long display, int unitID, ToolkitLock locker, boolean owner) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java index 5f3c220ca..7ab5bd6aa 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java @@ -63,7 +63,7 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl private static int fetchScreen(X11GraphicsDevice device, int screen) { // It still could be an AWT hold handle .. - if(X11Util.XineramaIsEnabled(device.getHandle())) { + if(X11Util.XineramaIsEnabled(device)) { screen = 0; // Xinerama -> 1 screen } return screen; diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 756e4451b..5eaaa6613 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -131,7 +131,7 @@ public interface AbstractGraphicsDevice extends Cloneable { /** * Optionally closing the device if handle is not null. *

- * The default implementation is a NOP, just setting the handle to null. + * The default implementation {@link ToolkitLock#dispose() dispose} it's {@link ToolkitLock} and sets the handle to null. *

*

* Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index 583fde07f..b16b0c75c 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -153,6 +153,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice @Override public boolean close() { + toolkitLock.dispose(); if(0 != handle) { handle = 0; return true; @@ -162,7 +163,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice @Override public String toString() { - return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+"]"; + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", "+toolkitLock+"]"; } /** diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index 40aaa8a25..4f4bb629b 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -33,7 +33,6 @@ package javax.media.nativewindow; -import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -43,6 +42,7 @@ import java.util.Map; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NativeWindowFactoryImpl; +import jogamp.nativewindow.ResourceToolkitLock; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; @@ -93,13 +93,6 @@ public abstract class NativeWindowFactory { private static ToolkitLock jawtUtilJAWTToolkitLock; - public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; - public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; - - private static Class x11JAWTToolkitLockClass; - private static Constructor x11JAWTToolkitLockConstructor; - private static Class x11ToolkitLockClass; - private static Constructor x11ToolkitLockConstructor; private static boolean requiresToolkitLock; private static volatile boolean isJVMShuttingDown = false; @@ -266,16 +259,6 @@ public abstract class NativeWindowFactory { // register either our default factory or (if exist) the X11/AWT one -> AWT Component registerFactory(ReflectionUtil.getClass(ReflectionUtil.AWTNames.ComponentClass, false, cl), factory); } - - if( TYPE_X11 == nativeWindowingTypePure ) { - // passing through RuntimeException if not exists intended - x11ToolkitLockClass = ReflectionUtil.getClass(X11ToolkitLockClassName, false, cl); - x11ToolkitLockConstructor = ReflectionUtil.getConstructor(x11ToolkitLockClass, new Class[] { long.class } ); - if( isAWTAvailable() ) { - x11JAWTToolkitLockClass = ReflectionUtil.getClass(X11JAWTToolkitLockClassName, false, cl); - x11JAWTToolkitLockConstructor = ReflectionUtil.getConstructor(x11JAWTToolkitLockClass, new Class[] { long.class } ); - } - } if(DEBUG) { System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock); @@ -300,6 +283,7 @@ public abstract class NativeWindowFactory { GraphicsConfigurationFactory.shutdown(); } shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown + // SharedResourceToolkitLock.shutdown(DEBUG); // not used yet if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown); } @@ -358,16 +342,9 @@ public abstract class NativeWindowFactory { /** * Provides the default {@link ToolkitLock} for type, a singleton instance. - *
*

    - *
  • If {@link #initSingleton(boolean) initSingleton( firstUIActionOnProcess := false )}
  • - *
      - *
    • If AWT-type and native-X11-type and AWT-available
    • - *
        - *
      • return {@link #getAWTToolkitLock()}
      • - *
      - *
    - *
  • Otherwise return {@link #getNullToolkitLock()}
  • + *
  • JAWT {@link ToolkitLock} if required and AWT available, otherwise
  • + *
  • {@link jogamp.nativewindow.NullToolkitLock}
  • *
*/ public static ToolkitLock getDefaultToolkitLock(String type) { @@ -390,84 +367,36 @@ public abstract class NativeWindowFactory { /** * Creates the default {@link ToolkitLock} for type and deviceHandle. - *
*
    - *
  • If {@link #initSingleton(boolean) initSingleton( firstUIActionOnProcess := false )}
  • - *
      - *
    • If X11 type
    • - *
        - *
      • return {@link jogamp.nativewindow.x11.X11ToolkitLock}
      • - *
      - *
    - *
  • Otherwise return {@link jogamp.nativewindow.NullToolkitLock}
  • + *
  • {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise
  • + *
  • {@link jogamp.nativewindow.NullToolkitLock}
  • *
*/ public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { if( requiresToolkitLock() ) { - if( TYPE_X11 == type ) { - if( 0== deviceHandle ) { - throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); - } - return createX11ToolkitLock(deviceHandle); - } + return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } /** * Creates the default {@link ToolkitLock} for type and deviceHandle. - *
*
    - *
  • If {@link #initSingleton(boolean) initSingleton( firstUIActionOnProcess := false )}
  • - *
      - *
    • If X11 type
    • - *
        - *
      • If shared-AWT-type and AWT available
      • - *
          - *
        • return {@link jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock}
        • - *
        - *
      • else return {@link jogamp.nativewindow.x11.X11ToolkitLock}
      • - *
      - *
    - *
  • Otherwise return {@link jogamp.nativewindow.NullToolkitLock}
  • + *
  • JAWT {@link ToolkitLock} if required and AWT available,
  • + *
  • {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise
  • + *
  • {@link jogamp.nativewindow.NullToolkitLock}
  • *
*/ public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) { if( requiresToolkitLock() ) { - if( TYPE_X11 == type ) { - if( 0== deviceHandle ) { - throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); - } - if( TYPE_AWT == sharedType && isAWTAvailable() ) { - return createX11AWTToolkitLock(deviceHandle); - } - return createX11ToolkitLock(deviceHandle); + if( TYPE_AWT == sharedType && isAWTAvailable() ) { + return getAWTToolkitLock(); } + return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } - - protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) { - try { - if(DEBUG) { - System.err.println("NativeWindowFactory.createX11AWTToolkitLock(0x"+Long.toHexString(deviceHandle)+")"); - // Thread.dumpStack(); - } - return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - protected static ToolkitLock createX11ToolkitLock(long deviceHandle) { - try { - return (ToolkitLock) x11ToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - + /** Returns the appropriate NativeWindowFactory to handle window objects of the given type. The windowClass might be {@link NativeWindow NativeWindow}, in which case the client has diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java index 30f9660f0..18b7cf5d9 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java @@ -33,12 +33,26 @@ import jogamp.nativewindow.Debug; /** * Marker for a singleton global recursive blocking lock implementation, * optionally locking a native windowing toolkit as well. - *
- * One use case is the AWT locking on X11, see {@link jogamp.nativewindow.jawt.JAWTToolkitLock}. + *

+ * Toolkit locks are created solely via {@link NativeWindowFactory}. + *

+ *

+ * One use case is the AWT locking on X11, see {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + *

*/ public interface ToolkitLock { public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true); public void lock(); public void unlock(); + + /** + * Dispose this instance. + *

+ * Shall be called when instance is no more required. + *

+ * This allows implementations sharing a lock via resources + * to decrease the reference counter. + */ + public void dispose(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java index 1af6bf279..e59910138 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java @@ -50,4 +50,13 @@ public class NullToolkitLock implements ToolkitLock { public final void unlock() { if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } } + + public final void dispose() { + // nop + } + + public String toString() { + return "NullToolkitLock[]"; + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java new file mode 100644 index 000000000..a3b0804fa --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java @@ -0,0 +1,74 @@ +/** + * Copyright 2012 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; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + *

+ * A resource handle maybe used within a unique object + * and can be synchronized across threads via an instance of ResourceToolkitLock. + *

+ */ +public class ResourceToolkitLock implements ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); + + public static final ResourceToolkitLock create() { + return new ResourceToolkitLock(); + } + + private final RecursiveLock lock; + + private ResourceToolkitLock() { + this.lock = LockFactory.createRecursiveLock(); + } + + + public final void lock() { + if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); } + lock.lock(); + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.unlock()"); } + lock.unlock(); + } + + public final void dispose() { + // nop + } + + public String toString() { + return "ResourceToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString()+"]"; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java new file mode 100644 index 000000000..5d7ae8abb --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -0,0 +1,141 @@ +/** + * Copyright 2012 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; + +import java.util.Iterator; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a shared resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + *

+ * A resource handle maybe used within many objects + * and can be synchronized across threads via an unique instance of SharedResourceToolkitLock. + *

+ *

+ * Implementation holds a synchronized map from handle to reference counted {@link SharedResourceToolkitLock}. + * New elements are added via {@link #get(long)} if new + * and removed via {@link #dispose()} if no more referenced. + *

+ */ +public class SharedResourceToolkitLock implements ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); + private static final LongObjectHashMap handle2Lock; + static { + handle2Lock = new LongObjectHashMap(); + handle2Lock.setKeyNotFoundValue(null); + } + + /** + * @return number of unclosed EGL Displays.
+ */ + public static int shutdown(boolean verbose) { + if(DEBUG || verbose || handle2Lock.size() > 0 ) { + System.err.println("SharedResourceToolkitLock: Shutdown (open: "+handle2Lock.size()+")"); + if(DEBUG) { + Thread.dumpStack(); + } + if( handle2Lock.size() > 0) { + dumpOpenDisplayConnections(); + } + } + return handle2Lock.size(); + } + + public static void dumpOpenDisplayConnections() { + System.err.println("SharedResourceToolkitLock: Open ResourceToolkitLock's: "+handle2Lock.size()); + int i=0; + for(Iterator iter = handle2Lock.iterator(); iter.hasNext(); i++) { + final LongObjectHashMap.Entry e = iter.next(); + System.err.println("SharedResourceToolkitLock: Open["+i+"]: "+e.value); + } + } + + public static final SharedResourceToolkitLock get(long handle) { + SharedResourceToolkitLock res; + synchronized(handle2Lock) { + res = (SharedResourceToolkitLock) handle2Lock.get(handle); + if( null == res ) { + res = new SharedResourceToolkitLock(handle); + res.refCount++; + handle2Lock.put(handle, res); + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * NEW *: "+res); } + } else { + res.refCount++; + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * EXIST *: "+res); } + } + } + return res; + } + + private final RecursiveLock lock; + private final long handle; + private volatile int refCount; + + private SharedResourceToolkitLock(long handle) { + this.lock = LockFactory.createRecursiveLock(); + this.handle = handle; + this.refCount = 0; + } + + + public final void lock() { + if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); } + lock.lock(); + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.unlock()"); } + lock.unlock(); + } + + public final void dispose() { + if(0 < refCount) { // volatile OK + synchronized(handle2Lock) { + refCount--; + if(0 == refCount) { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * REMOV *: "+this); } + handle2Lock.remove(handle); + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * DOWN *: "+this); } + } + } + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * NULL *: "+this); } + } + } + + public String toString() { + return "SharedResourceToolkitLock[refCount "+refCount+", handle 0x"+Long.toHexString(handle)+", obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString()+"]"; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index f1e8a786a..7c934b154 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -237,6 +237,9 @@ public class JAWTUtil { public final void unlock() { JAWTUtil.unlockToolkit(); } + public final void dispose() { + // nop + } }; // trigger native AWT toolkit / properties initialization diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java deleted file mode 100644 index 743d371b7..000000000 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright 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: - * - * 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.jawt.x11; - -import jogamp.nativewindow.jawt.*; -import jogamp.nativewindow.x11.X11Lib; -import jogamp.nativewindow.x11.X11Util; -import javax.media.nativewindow.ToolkitLock; - -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; - -/** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. - *
- * This strategy should only be used if AWT is using the underlying native windowing toolkit - * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call - * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets. - */ -public class X11JAWTToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; - - public X11JAWTToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } - } - - public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } - JAWTUtil.lockToolkit(); - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); - } - } - - public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } - JAWTUtil.unlockToolkit(); - } -} diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 736718de8..467809284 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -127,7 +127,8 @@ public class X11JAWTWindow extends JAWTWindow { } protected Point getLocationOnScreenNativeImpl(int x, int y) { - return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + // surface is locked and hence the device + return X11Lib.GetRelativeLocation(getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java deleted file mode 100644 index 5166ef577..000000000 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 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: - * - * 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.x11; - -import javax.media.nativewindow.ToolkitLock; - -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; - -/** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing {@link X11Util#XLockDisplay(long)}. - *
- * This strategy should not be used in case XInitThreads() is being used, - * or a higher level toolkit lock is required, ie AWT lock. - */ -public class X11ToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; - - public X11ToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } - } - - public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); - } - } - - public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } - } -} diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 2ea75c7fb..60f54eb3c 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -42,8 +42,8 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; - import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; /** * Contains a thread safe X11 utility to retrieve display connections. @@ -80,25 +80,15 @@ public class X11Util { */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG", true); - /** Value is true, best 'stable' results if always using XInitThreads(). */ - public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; - - /** Value is true, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ - public static final boolean HAS_XLOCKDISPLAY_BUG = true; - public static final boolean DEBUG = Debug.debug("X11Util"); 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 boolean isX11LockAvailable = false; - private static boolean requiresX11Lock = true; private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues - private static int setX11ErrorHandlerRecCount = 0; private static Object setX11ErrorHandlerLock = new Object(); - /** * Called by {@link NativeWindowFactory#initSingleton()} @@ -115,9 +105,7 @@ public class X11Util { throw new NativeWindowException("NativeWindow X11 native library load error."); } - final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED ; - final boolean isXInitThreadsOK = initialize0( callXInitThreads, XERROR_STACKDUMP); - isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; + final boolean isInitOK = initialize0( XERROR_STACKDUMP ); final long dpy = X11Lib.XOpenDisplay(null); if(0 != dpy) { @@ -134,9 +122,7 @@ public class X11Util { } if(DEBUG) { - System.err.println("X11Util requiresX11Lock "+requiresX11Lock+ - ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ - ", isX11LockAvailable "+isX11LockAvailable+ + System.err.println("X11Util init OK "+isInitOK+"]"+ ", X11 Display(NULL) <"+nullDisplayName+">"+ ", XSynchronize Enabled: "+XSYNC_ENABLED); // Thread.dumpStack(); @@ -199,31 +185,14 @@ public class X11Util { } } } - - public static synchronized boolean isNativeLockAvailable() { - return isX11LockAvailable; - } - - public static synchronized boolean requiresToolkitLock() { - return requiresX11Lock; + + public static boolean requiresToolkitLock() { + return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock. } - + public static void setX11ErrorHandler(boolean onoff, boolean quiet) { synchronized(setX11ErrorHandlerLock) { - if(onoff) { - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(true, quiet); - } - setX11ErrorHandlerRecCount++; - } else { - if(0 >= setX11ErrorHandlerRecCount) { - throw new InternalError(); - } - setX11ErrorHandlerRecCount--; - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(false, false); - } - } + setX11ErrorHandler0(onoff, quiet); } } @@ -492,52 +461,50 @@ public class X11Util { *******************************/ public static long XOpenDisplay(String arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - long handle = X11Lib.XOpenDisplay(arg0); - if(XSYNC_ENABLED && 0 != handle) { - X11Lib.XSynchronize(handle, true); - } - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - // Thread.dumpStack(); - } - return handle; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + long handle = X11Lib.XOpenDisplay(arg0); + if(XSYNC_ENABLED && 0 != handle) { + X11Lib.XSynchronize(handle, true); + } + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); } + return handle; } public static int XCloseDisplay(long display) { - NativeWindowFactory.getDefaultToolkitLock().lock(); + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); + } + int res = -1; try { - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - // Thread.dumpStack(); - } - int res = -1; - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - res = X11Lib.XCloseDisplay(display); - } catch (Exception ex) { - System.err.println("X11Util: Catched Exception:"); - ex.printStackTrace(); - } finally { - X11Util.setX11ErrorHandler(false, false); - } - return res; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + res = X11Lib.XCloseDisplay(display); + } catch (Exception ex) { + System.err.println("X11Util: Catched Exception:"); + ex.printStackTrace(); } + return res; } static volatile boolean XineramaFetched = false; static long XineramaLibHandle = 0; static long XineramaQueryFunc = 0; - public static boolean XineramaIsEnabled(long display) { - if(0==display) { - throw new IllegalArgumentException("Display NULL"); + public static boolean XineramaIsEnabled(X11GraphicsDevice device) { + if(null == device) { + throw new IllegalArgumentException("X11 Display device is NULL"); + } + device.lock(); + try { + return XineramaIsEnabled(device.getHandle()); + } finally { + device.unlock(); + } + } + public static boolean XineramaIsEnabled(long displayHandle) { + if( 0 == displayHandle ) { + throw new IllegalArgumentException("X11 Display handle is NULL"); } if(!XineramaFetched) { // volatile: ok synchronized(X11Util.class) { @@ -551,9 +518,9 @@ public class X11Util { } } if(0!=XineramaQueryFunc) { - final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, display); + final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, displayHandle); if(DEBUG) { - System.err.println("XineramaIsEnabled: "+res); + System.err.println("XineramaIsEnabled: 0x"+Long.toHexString(displayHandle)+": "+res); } return res; } else if(DEBUG) { @@ -566,7 +533,7 @@ public class X11Util { private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI - private static native boolean initialize0(boolean firstUIActionOnProcess, boolean debug); + private static native boolean initialize0(boolean debug); private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java index 1de03e8be..b152f0f97 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -91,7 +91,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); final long displayHandle; - boolean owner = false; + final boolean owner; if(0==displayHandleAWT) { displayHandle = X11Util.openDisplay(null); owner = true; @@ -112,9 +112,8 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println(getThreadName()+" - X11AWTGraphicsConfigurationFactory: AWT dpy "+displayName+" / "+toHexString(displayHandleAWT)+", create X11 display "+toHexString(displayHandle)); } } - final ToolkitLock lock = owner ? - NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock - NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle); + // Global JAWT lock required - No X11 resource locking due to private display connection + final ToolkitLock lock = NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT); final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); if(DEBUG) { diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index fcba8580c..afdd413eb 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -178,11 +178,14 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) char threadName[80]; char errCodeStr[80]; char reqCodeStr[80]; - int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv *jniEnv = NULL; + if( errorHandlerDebug || errorHandlerThrowException ) { + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + } (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); @@ -191,7 +194,7 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); - if( errorHandlerDebug ) { + if( errorHandlerDebug && NULL != jniEnv ) { (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); } @@ -246,16 +249,17 @@ static int x11IOErrorHandler(Display *dpy) { const char * dpyName = XDisplayName(NULL); const char * errnoStr = strerror(errno); - char threadName[80]; int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + JNIEnv *jniEnv = NULL; - fprintf(stderr, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s\n", threadName, dpy, dpyName, errnoStr); + fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr); (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if (NULL != jniEnv) { + char threadName[80]; + (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); if (shallBeDetached) { @@ -305,6 +309,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0 /* no dpy, no sync */); _initialized=1; if(JNI_TRUE == debug) { fprintf(stderr, "Info: NativeWindow native init passed\n"); @@ -315,6 +320,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0 /* no dpy, no sync */); x11IOErrorHandlerEnable(0, env); } @@ -347,7 +353,7 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja } NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -382,7 +388,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u } else { r = 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); return r; } @@ -396,7 +402,7 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, } NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); return r; } @@ -439,7 +445,7 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused } NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); return _res; } @@ -497,7 +503,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -541,7 +547,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow XSelectInput(dpy, window, 0); // no events - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -569,7 +575,7 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); } /* @@ -597,7 +603,7 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 1e9a0e9eb..391bccf3d 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -113,16 +113,22 @@ public abstract class Display { */ public abstract int removeReference(); + /** + * Return the {@link AbstractGraphicsDevice} used for depending resources lifecycle, + * i.e. {@link Screen} and {@link Window}, as well as the event dispatching (EDT). */ public abstract AbstractGraphicsDevice getGraphicsDevice(); /** - * @return the fully qualified Display name, - * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()} + * Return the handle of the {@link AbstractGraphicsDevice} as returned by {@link #getGraphicsDevice()}. */ - public abstract String getFQName(); - public abstract long getHandle(); + /** + * @return The fully qualified Display name, + * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()}. + */ + public abstract String getFQName(); + /** * @return this display internal serial id */ @@ -141,6 +147,9 @@ public abstract class Display { */ public abstract String getType(); + /** Return true if this instance is exclusive, i.e. will not be shared. */ + public abstract boolean isExclusive(); + /** * Sets a new {@link EDTUtil} and returns the previous one. *

@@ -183,11 +192,12 @@ public abstract class Display { * * @param type * @param name - * @param fromIndex start index, then increasing until found or end of list * + * @param fromIndex start index, then increasing until found or end of list + * @paran shared if true, only shared instances are found, otherwise also exclusive * @return */ - public static Display getFirstDisplayOf(String type, String name, int fromIndex) { - return getDisplayOfImpl(type, name, fromIndex, 1); + public static Display getFirstDisplayOf(String type, String name, int fromIndex, boolean shared) { + return getDisplayOfImpl(type, name, fromIndex, 1, shared); } /** @@ -195,19 +205,22 @@ public abstract class Display { * @param type * @param name * @param fromIndex start index, then decreasing until found or end of list. -1 is interpreted as size - 1. + * @paran shared if true, only shared instances are found, otherwise also exclusive * @return */ - public static Display getLastDisplayOf(String type, String name, int fromIndex) { - return getDisplayOfImpl(type, name, fromIndex, -1); + public static Display getLastDisplayOf(String type, String name, int fromIndex, boolean shared) { + return getDisplayOfImpl(type, name, fromIndex, -1, shared); } - private static Display getDisplayOfImpl(String type, String name, int fromIndex, int incr) { + private static Display getDisplayOfImpl(String type, String name, int fromIndex, int incr, boolean shared) { synchronized(displayList) { int i = fromIndex >= 0 ? fromIndex : displayList.size() - 1 ; while( ( incr > 0 ) ? i < displayList.size() : i >= 0 ) { Display display = (Display) displayList.get(i); if( display.getType().equals(type) && - display.getName().equals(name) ) { + display.getName().equals(name) && + ( !shared || shared && !display.isExclusive() ) + ) { return display; } i+=incr; diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index abae94ab6..1bf47f4aa 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -305,7 +305,7 @@ public class NewtFactory { * Instantiate a Display entity using the native handle. */ public static Display createDisplay(String type, long handle, boolean reuse) { - return DisplayImpl.create(type, null, handle, false); + return DisplayImpl.create(type, null, handle, reuse); } public static boolean isScreenCompatible(NativeWindow parent, Screen childScreen) { diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index 26f19ad6b..cfbcc988a 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -145,7 +145,7 @@ public abstract class Screen { public abstract Display getDisplay(); /** - * @return the screen fully qualified Screen name, + * @return The screen fully qualified Screen name, * which is a key of {@link com.jogamp.newt.Display#getFQName()} + {@link #getIndex()}. */ public abstract String getFQName(); diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index bca7f6e5b..daeb3e886 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -42,6 +42,7 @@ import com.jogamp.newt.event.NEWTEventConsumer; import jogamp.newt.event.NEWTEventTask; import com.jogamp.newt.util.EDTUtil; import java.util.ArrayList; + import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; @@ -66,7 +67,7 @@ public abstract class DisplayImpl extends Display { name = display.validateDisplayName(name, handle); synchronized(displayList) { if(reuse) { - Display display0 = Display.getLastDisplayOf(type, name, -1); + Display display0 = Display.getLastDisplayOf(type, name, -1, true /* shared only */); if(null != display0) { if(DEBUG) { System.err.println("Display.create() REUSE: "+display0+" "+getThreadName()); @@ -74,9 +75,9 @@ public abstract class DisplayImpl extends Display { return display0; } } + display.exclusive = !reuse; display.name = name; display.type=type; - display.destroyWhenUnused=false; display.refCount=0; display.id = serialno++; display.fqname = getFQName(display.type, display.name, display.id); @@ -94,7 +95,7 @@ public abstract class DisplayImpl extends Display { throw new RuntimeException(e); } } - + @Override public boolean equals(Object obj) { if (obj == null) { @@ -116,10 +117,12 @@ public abstract class DisplayImpl extends Display { return true; } + @Override public int hashCode() { return hashCode; } + @Override public synchronized final void createNative() throws NativeWindowException { @@ -148,10 +151,6 @@ public abstract class DisplayImpl extends Display { } } - protected boolean shallRunOnEDT() { - return true; - } - protected EDTUtil createEDTUtil() { final EDTUtil def; if(NewtFactory.useEDT()) { @@ -179,12 +178,7 @@ public abstract class DisplayImpl extends Display { if(DEBUG) { System.err.println("Display.setEDTUtil: "+oldEDTUtil+" -> "+newEDTUtil); } - if(null != oldEDTUtil) { - stopEDT( new Runnable() { public void run() {} } ); - // ready for restart .. - oldEDTUtil.waitUntilStopped(); - oldEDTUtil.reset(); - } + removeEDT( new Runnable() { public void run() {} } ); edtUtil = newEDTUtil; return oldEDTUtil; } @@ -194,16 +188,19 @@ public abstract class DisplayImpl extends Display { return edtUtil; } - private void stopEDT(final Runnable task) { - if( shallRunOnEDT() && null!=edtUtil ) { + private void removeEDT(final Runnable task) { + if(null!=edtUtil) { edtUtil.invokeStop(task); + // ready for restart .. + edtUtil.waitUntilStopped(); + edtUtil.reset(); } else { task.run(); } } public void runOnEDTIfAvail(boolean wait, final Runnable task) { - if( shallRunOnEDT() && null!=edtUtil && !edtUtil.isCurrentThreadEDT()) { + if( null!=edtUtil && !edtUtil.isCurrentThreadEDT()) { edtUtil.invoke(wait, task); } else { task.run(); @@ -212,18 +209,17 @@ public abstract class DisplayImpl extends Display { public boolean validateEDT() { if(0==refCount && null==aDevice && null != edtUtil && edtUtil.isRunning()) { - stopEDT( new Runnable() { + removeEDT( new Runnable() { public void run() { // nop } } ); - edtUtil.waitUntilStopped(); - edtUtil.reset(); return true; } return false; } + @Override public synchronized final void destroy() { if(DEBUG) { dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); @@ -239,17 +235,13 @@ public abstract class DisplayImpl extends Display { } final AbstractGraphicsDevice f_aDevice = aDevice; final DisplayImpl f_dpy = this; - stopEDT( new Runnable() { + removeEDT( new Runnable() { public void run() { if ( null != f_aDevice ) { f_dpy.closeNativeImpl(); } } } ); - if(null!=edtUtil) { - edtUtil.waitUntilStopped(); - edtUtil.reset(); - } aDevice = null; refCount=0; if(DEBUG) { @@ -290,21 +282,30 @@ public abstract class DisplayImpl extends Display { protected abstract void createNativeImpl(); protected abstract void closeNativeImpl(); + @Override public final int getId() { return id; } + @Override public final String getType() { return type; } + @Override public final String getName() { return name; } + @Override public final String getFQName() { return fqname; } + + @Override + public final boolean isExclusive() { + return exclusive; + } public static final String nilString = "nil" ; @@ -324,9 +325,10 @@ public abstract class DisplayImpl extends Display { sb.append(name); sb.append("-"); sb.append(id); - return sb.toString().intern(); + return sb.toString(); } + @Override public final long getHandle() { if(null!=aDevice) { return aDevice.getHandle(); @@ -334,14 +336,17 @@ public abstract class DisplayImpl extends Display { return 0; } + @Override public final AbstractGraphicsDevice getGraphicsDevice() { return aDevice; } + @Override public synchronized final boolean isNativeValid() { return null != aDevice; } + @Override public boolean isEDTRunning() { if(null!=edtUtil) { return edtUtil.isRunning(); @@ -351,7 +356,7 @@ public abstract class DisplayImpl extends Display { @Override public String toString() { - return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; + return "NEWT-Display["+getFQName()+", excl "+exclusive+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; } protected abstract void dispatchMessagesNative(); @@ -403,6 +408,7 @@ public abstract class DisplayImpl extends Display { eventTask.notifyCaller(); } + @Override public void dispatchMessages() { // System.err.println("Display.dispatchMessages() 0 "+this+" "+getThreadName()); if(0==refCount || // no screens @@ -475,20 +481,23 @@ public abstract class DisplayImpl extends Display { public interface DisplayRunnable { T run(long dpy); } - public final T runWithLockedDisplayHandle(DisplayRunnable action) { - final AbstractGraphicsDevice aDevice = getGraphicsDevice(); - if(null == aDevice) { - throw new RuntimeException("null device - not initialized: "+this); - } + public static final T runWithLockedDevice(AbstractGraphicsDevice device, DisplayRunnable action) { T res; - aDevice.lock(); + device.lock(); try { - res = action.run(aDevice.getHandle()); + res = action.run(device.getHandle()); } finally { - aDevice.unlock(); + device.unlock(); } return res; } + public final T runWithLockedDisplayDevice(DisplayRunnable action) { + final AbstractGraphicsDevice device = getGraphicsDevice(); + if(null == device) { + throw new RuntimeException("null device - not initialized: "+this); + } + return runWithLockedDevice(device, action); + } protected EDTUtil edtUtil = null; protected int id; @@ -497,7 +506,7 @@ public abstract class DisplayImpl extends Display { protected String fqname; protected int hashCode; protected int refCount; // number of Display references by Screen - protected boolean destroyWhenUnused; + protected boolean exclusive; // do not share this display, uses NullLock! protected AbstractGraphicsDevice aDevice; } diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index e2c0f746f..1cc53e80e 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -42,7 +42,6 @@ import java.util.List; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.util.Dimension; import javax.media.nativewindow.util.DimensionImmutable; import javax.media.nativewindow.util.Point; @@ -130,7 +129,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { } } screen.screen_idx = idx; - screen.fqname = (display.getFQName()+idx).intern(); + screen.fqname = display.getFQName()+"-s"+idx; screen.hashCode = screen.fqname.hashCode(); screenList.add(screen); if(DEBUG) { diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index c1ac87d38..79770189b 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -85,7 +85,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private volatile long windowHandle = 0; // lifecycle critical private volatile boolean visible = false; // lifecycle critical private RecursiveLock windowLock = LockFactory.createRecursiveLock(); // Window instance wide lock - private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); // Surface only lock + private int surfaceLockCount = 0; // surface lock recursion count private ScreenImpl screen; // never null after create - may change reference though (reparent) private boolean screenReferenceAdded = false; @@ -553,10 +553,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final int lockSurface() throws NativeWindowException, RuntimeException { final RecursiveLock _wlock = windowLock; - final RecursiveLock _slock = surfaceLock; _wlock.lock(); - _slock.lock(); - int res = _slock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? + surfaceLockCount++; + int res = ( 1 == surfaceLockCount ) ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { try { @@ -573,7 +572,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } finally { if (LOCK_SURFACE_NOT_READY >= res) { - _slock.unlock(); _wlock.unlock(); } } @@ -583,12 +581,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final void unlockSurface() { - final RecursiveLock _slock = surfaceLock; final RecursiveLock _wlock = windowLock; - _slock.validateLocked(); _wlock.validateLocked(); - if (_slock.getHoldCount() == 1) { + if ( 1 == surfaceLockCount ) { final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); @@ -596,42 +592,48 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer adevice.unlock(); } } - _slock.unlock(); + surfaceLockCount--; _wlock.unlock(); } @Override public final boolean isSurfaceLockedByOtherThread() { - return surfaceLock.isLockedByOtherThread(); + return windowLock.isLockedByOtherThread(); } @Override public final Thread getSurfaceLockOwner() { - return surfaceLock.getOwner(); + return windowLock.getOwner(); } public final RecursiveLock getLock() { return windowLock; } + @Override public long getSurfaceHandle() { return windowHandle; // default: return window handle } + @Override public boolean surfaceSwap() { return false; } + @Override public final AbstractGraphicsConfiguration getGraphicsConfiguration() { return config.getNativeGraphicsConfiguration(); } - public final long getDisplayHandle() { - return getScreen().getDisplay().getHandle(); + @Override + public long getDisplayHandle() { + // Actually: return getGraphicsConfiguration().getScreen().getDevice().getHandle(); + return screen.getDisplay().getHandle(); // shortcut } + @Override public final int getScreenIndex() { - return getScreen().getIndex(); + return screen.getIndex(); } //---------------------------------------------------------------------- @@ -1554,8 +1556,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer for (int i = 0; i < keyListeners.size(); i++ ) { sb.append(keyListeners.get(i)+", "); } - sb.append("], surfaceLock "+surfaceLock); - sb.append(", windowLock "+windowLock+"]"); + sb.append("], windowLock "+windowLock+"]"); return sb.toString(); } diff --git a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java index 70e9ba570..ead567d82 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java @@ -66,7 +66,9 @@ public class DisplayDriver extends DisplayImpl { return def; } - protected void closeNativeImpl() { } + protected void closeNativeImpl() { + aDevice.close(); + } protected void dispatchMessagesNative() { /* nop */ } } diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java index 65ca63eec..cc55c336e 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java @@ -39,6 +39,7 @@ import javax.media.nativewindow.NativeWindowException; import jogamp.newt.NEWTJNILibLoader; import jogamp.opengl.egl.EGL; +import jogamp.opengl.egl.EGLDisplayUtil; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; @@ -72,6 +73,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { if (aDevice.getHandle() != EGL.EGL_NO_DISPLAY) { DestroyDisplay(aDevice.getHandle()); } + aDevice.close(); } protected void dispatchMessagesNative() { diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java index 97c384d33..e370038d9 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java @@ -84,6 +84,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { } } } + aDevice.close(); } protected void dispatchMessagesNative() { diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java index 1a3f14859..b49c6b6e0 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java @@ -72,7 +72,9 @@ public class DisplayDriver extends DisplayImpl { aDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { } + protected void closeNativeImpl() { + aDevice.close(); + } public static void runNSApplication() { runNSApplication0(); diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java index 579ec5be8..615f9e63b 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java @@ -73,6 +73,7 @@ public class DisplayDriver extends DisplayImpl { protected void closeNativeImpl() { sharedClassFactory.releaseSharedClass(); + aDevice.close(); } protected void dispatchMessagesNative() { diff --git a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java index 714324d63..bff050030 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java @@ -36,7 +36,6 @@ package jogamp.newt.driver.x11; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -74,71 +73,48 @@ public class DisplayDriver extends DisplayImpl { * {@inheritDoc} * * We use a private non-shared X11 Display instance for EDT window operations and one for exposed animation, eg. OpenGL. - *

- * In case {@link X11Util#HAS_XLOCKDISPLAY_BUG} and {@link X11Util#XINITTHREADS_ALWAYS_ENABLED}, - * we use null locking. Even though this seems not to be rational, it gives most stable results on all platforms. - *

- *

- * Otherwise we use basic locking via the constructor {@link X11GraphicsDevice#X11GraphicsDevice(long, int, boolean)}, - * since it is possible to share this device via {@link com.jogamp.newt.NewtFactory#createDisplay(String, boolean)}. - *

*/ - @SuppressWarnings("unused") protected void createNativeImpl() { + X11Util.setX11ErrorHandler(true, DEBUG ? false : true); // make sure X11 error handler is set long handle = X11Util.openDisplay(name); if( 0 == handle ) { throw new RuntimeException("Error creating display(Win): "+name); } - if(USE_SEPARATE_DISPLAY_FOR_EDT) { - edtDisplayHandle = X11Util.openDisplay(name); - if( 0 == edtDisplayHandle ) { - X11Util.closeDisplay(handle); - throw new RuntimeException("Error creating display(EDT): "+name); - } - } else { - edtDisplayHandle = handle; - } + aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, true); try { - CompleteDisplay0(edtDisplayHandle); + CompleteDisplay0(aDevice.getHandle()); } catch(RuntimeException e) { closeNativeImpl(); throw e; - } - - // see API doc above! - if(X11Util.XINITTHREADS_ALWAYS_ENABLED && X11Util.HAS_XLOCKDISPLAY_BUG) { - aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock(), false); - } else { - aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, false); - } + } } protected void closeNativeImpl() { - DisplayRelease0(edtDisplayHandle, javaObjectAtom, windowDeleteAtom); + DisplayRelease0(aDevice.getHandle(), javaObjectAtom, windowDeleteAtom); javaObjectAtom = 0; windowDeleteAtom = 0; - // closing using ATI driver bug 'same order' - final long handle = getHandle(); - X11Util.closeDisplay(handle); - if(handle != edtDisplayHandle) { - X11Util.closeDisplay(edtDisplayHandle); - } - edtDisplayHandle = 0; + aDevice.close(); // closes X11 display } protected void dispatchMessagesNative() { - if(0 != edtDisplayHandle) { - DispatchMessages0(edtDisplayHandle, javaObjectAtom, windowDeleteAtom); + aDevice.lock(); + try { + final long handle = aDevice.getHandle(); + if(0 != handle) { + DispatchMessages0(handle, javaObjectAtom, windowDeleteAtom); + } + } finally { + aDevice.unlock(); } } - protected long getEDTHandle() { return edtDisplayHandle; } protected long getJavaObjectAtom() { return javaObjectAtom; } protected long getWindowDeleteAtom() { return windowDeleteAtom; } //---------------------------------------------------------------------- // Internals only // + private static native boolean initIDs0(boolean debug); private native void CompleteDisplay0(long handle); @@ -151,17 +127,6 @@ public class DisplayDriver extends DisplayImpl { private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom); - /** - * 2011/06/14 libX11 1.4.2 and libxcb 1.7 bug 20708 - Multithreading Issues w/ OpenGL, .. - * https://bugs.freedesktop.org/show_bug.cgi?id=20708 - * https://jogamp.org/bugzilla/show_bug.cgi?id=502 - * Affects: Ubuntu 11.04, OpenSuSE 11, .. - * Workaround: Using a separate X11 Display connection for event dispatching (EDT) - */ - private final boolean USE_SEPARATE_DISPLAY_FOR_EDT = true; - - private long edtDisplayHandle; - /** X11 Window delete atom marker used on EDT */ private long windowDeleteAtom; diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index 10f6b84da..b09d98e06 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -59,7 +59,7 @@ public class ScreenDriver extends ScreenImpl { protected void createNativeImpl() { // validate screen index - Long handle = display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + Long handle = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public Long run(long dpy) { return new Long(GetScreen0(dpy, screen_idx)); } } ); @@ -81,7 +81,7 @@ public class ScreenDriver extends ScreenImpl { private int nmode_number; protected int[] getScreenModeFirstImpl() { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public int[] run(long dpy) { // initialize iterators and static data nrotations = getAvailableScreenModeRotations0(dpy, screen_idx); @@ -110,7 +110,7 @@ public class ScreenDriver extends ScreenImpl { protected int[] getScreenModeNextImpl() { // assemble: w x h x bpp x f x r - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public int[] run(long dpy) { /** System.err.println("******** mode: "+nmode_number); @@ -176,7 +176,7 @@ public class ScreenDriver extends ScreenImpl { } protected ScreenMode getCurrentScreenModeImpl() { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public ScreenMode run(long dpy) { long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx); if(0 == screenConfigHandle) { @@ -237,7 +237,7 @@ public class ScreenDriver extends ScreenImpl { throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode); } final long t0 = System.currentTimeMillis(); - boolean done = runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + boolean done = runWithTempDisplayHandle( new DisplayImpl.DisplayRunnable() { public Boolean run(long dpy) { boolean done = false; long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx); @@ -276,23 +276,21 @@ public class ScreenDriver extends ScreenImpl { return done; } - private class XineramaEnabledQuery implements DisplayImpl.DisplayRunnable { + private DisplayImpl.DisplayRunnable xineramaEnabledQueryWithTemp = new DisplayImpl.DisplayRunnable() { public Boolean run(long dpy) { return new Boolean(X11Util.XineramaIsEnabled(dpy)); - } - } - private XineramaEnabledQuery xineramaEnabledQuery = new XineramaEnabledQuery(); + } }; protected int validateScreenIndex(final int idx) { if(getDisplay().isNativeValid()) { - return runWithLockedDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx; + return X11Util.XineramaIsEnabled((X11GraphicsDevice)getDisplay().getGraphicsDevice()) ? 0 : idx; } else { - return runWithTempDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx; + return runWithTempDisplayHandle( xineramaEnabledQueryWithTemp ).booleanValue() ? 0 : idx; } } protected void getVirtualScreenOriginAndSize(final Point virtualOrigin, final Dimension virtualSize) { - display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public Object run(long dpy) { virtualOrigin.setX(0); virtualOrigin.setY(0); @@ -305,10 +303,8 @@ public class ScreenDriver extends ScreenImpl { //---------------------------------------------------------------------- // Internals only // - private final T runWithLockedDisplayHandle(DisplayRunnable action) { - return display.runWithLockedDisplayHandle(action); - // return runWithTempDisplayHandle(action); - // return runWithoutLock(action); + private final T runWithLockedDisplayDevice(DisplayRunnable action) { + return display.runWithLockedDisplayDevice(action); } private final T runWithTempDisplayHandle(DisplayRunnable action) { @@ -324,9 +320,6 @@ public class ScreenDriver extends ScreenImpl { } return res; } - private final T runWithoutLock(DisplayRunnable action) { - return action.run(display.getHandle()); - } private static native long GetScreen0(long dpy, int scrn_idx); diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index 97d1ae3db..aea86a420 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -35,6 +35,7 @@ package jogamp.newt.driver.x11; import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; import jogamp.newt.DisplayImpl; import jogamp.newt.DisplayImpl.DisplayRunnable; import jogamp.newt.WindowImpl; @@ -44,6 +45,8 @@ import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsScreen; import com.jogamp.newt.event.MouseEvent; public class WindowDriver extends WindowImpl { @@ -63,9 +66,19 @@ public class WindowDriver extends WindowImpl { protected void createNativeImpl() { final ScreenDriver screen = (ScreenDriver) getScreen(); final DisplayDriver display = (DisplayDriver) screen.getDisplay(); + final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice(); + + // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering + final long renderDeviceHandle = X11Util.openDisplay(edtDevice.getConnection()); + if( 0 == renderDeviceHandle ) { + throw new RuntimeException("Error creating display(EDT): "+edtDevice.getConnection()); + } + renderDevice = new X11GraphicsDevice(renderDeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true); + AbstractGraphicsScreen renderScreen = new X11GraphicsScreen((X11GraphicsDevice) renderDevice, screen.getIndex()); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice(), capsRequested); final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); + capsRequested, capsRequested, capabilitiesChooser, renderScreen, VisualIDHolder.VID_UNDEFINED); if(DEBUG_IMPLEMENTATION) { System.err.println("X11Window.createNativeImpl() factory: "+factory+", chosen config: "+cfg); } @@ -78,11 +91,16 @@ public class WindowDriver extends WindowImpl { } setGraphicsConfiguration(cfg); final int flags = getReconfigureFlags(0, true) & - ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; - setWindowHandle(CreateWindow0(getParentWindowHandle(), - display.getEDTHandle(), screen.getIndex(), visualID, - display.getJavaObjectAtom(), display.getWindowDeleteAtom(), - getX(), getY(), getWidth(), getHeight(), autoPosition(), flags)); + ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; + edtDevice.lock(); + try { + setWindowHandle(CreateWindow0(getParentWindowHandle(), + edtDevice.getHandle(), screen.getIndex(), visualID, + display.getJavaObjectAtom(), display.getWindowDeleteAtom(), + getX(), getY(), getWidth(), getHeight(), autoPosition(), flags)); + } finally { + edtDevice.unlock(); + } windowHandleClose = getWindowHandle(); if (0 == windowHandleClose) { throw new NativeWindowException("Error creating window"); @@ -92,8 +110,10 @@ public class WindowDriver extends WindowImpl { protected void closeNativeImpl() { if(0!=windowHandleClose && null!=getScreen() ) { DisplayDriver display = (DisplayDriver) getScreen().getDisplay(); + final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice(); + edtDevice.lock(); try { - CloseWindow0(display.getEDTHandle(), windowHandleClose, + CloseWindow0(edtDevice.getHandle(), windowHandleClose, display.getJavaObjectAtom(), display.getWindowDeleteAtom()); } catch (Throwable t) { if(DEBUG_IMPLEMENTATION) { @@ -101,28 +121,47 @@ public class WindowDriver extends WindowImpl { e.printStackTrace(); } } finally { + edtDevice.unlock(); windowHandleClose = 0; } } + if(null != renderDevice) { + renderDevice.close(); // closes X11 display + renderDevice = null; + } } - protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { + @Override + public long getDisplayHandle() { + // Actually: return getGraphicsConfiguration().getScreen().getDevice().getHandle(); + return renderDevice.getHandle(); // shortcut + } + + protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { if(DEBUG_IMPLEMENTATION) { System.err.println("X11Window reconfig: "+x+"/"+y+" "+width+"x"+height+", "+ getReconfigureFlagsAsString(null, flags)); } + final int _x, _y; if(0 == ( FLAG_IS_UNDECORATED & flags)) { final InsetsImmutable i = getInsets(); // client position -> top-level window position - x -= i.getLeftWidth() ; - y -= i.getTopHeight() ; + _x = x - i.getLeftWidth() ; + _y = y - i.getTopHeight() ; + } else { + _x = x; + _y = y; } final DisplayDriver display = (DisplayDriver) getScreen().getDisplay(); - reconfigureWindow0( getDisplayEDTHandle(), getScreenIndex(), - getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(), - x, y, width, height, flags); - + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { + public Object run(long dpy) { + reconfigureWindow0( dpy, getScreenIndex(), + getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(), + _x, _y, width, height, flags); + return null; + } + }); return true; } @@ -133,13 +172,18 @@ public class WindowDriver extends WindowImpl { } } - protected void requestFocusImpl(boolean force) { - requestFocus0(getDisplayEDTHandle(), getWindowHandle(), force); + protected void requestFocusImpl(final boolean force) { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { + public Object run(long dpy) { + requestFocus0(dpy, getWindowHandle(), force); + return null; + } + }); } @Override protected void setTitleImpl(final String title) { - runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public Object run(long dpy) { setTitle0(dpy, getWindowHandle(), title); return null; @@ -149,35 +193,38 @@ public class WindowDriver extends WindowImpl { @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public Boolean run(long dpy) { - return Boolean.valueOf(setPointerVisible0(getDisplayEDTHandle(), getWindowHandle(), pointerVisible)); + return Boolean.valueOf(setPointerVisible0(dpy, getWindowHandle(), pointerVisible)); } }).booleanValue(); } @Override protected boolean confinePointerImpl(final boolean confine) { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public Boolean run(long dpy) { - return Boolean.valueOf(confinePointer0(getDisplayEDTHandle(), getWindowHandle(), confine)); + return Boolean.valueOf(confinePointer0(dpy, getWindowHandle(), confine)); } }).booleanValue(); } @Override protected void warpPointerImpl(final int x, final int y) { - runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { public Object run(long dpy) { - warpPointer0(getDisplayEDTHandle(), getWindowHandle(), x, y); + warpPointer0(dpy, getWindowHandle(), x, y); return null; } }); } protected Point getLocationOnScreenImpl(final int x, final int y) { - // X11Util.GetRelativeLocation: locks display already ! - return X11Lib.GetRelativeLocation( getScreen().getDisplay().getHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { + public Point run(long dpy) { + return X11Lib.GetRelativeLocation(dpy, getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + } + } ); } protected void updateInsetsImpl(Insets insets) { @@ -229,16 +276,11 @@ public class WindowDriver extends WindowImpl { //---------------------------------------------------------------------- // Internals only // - private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI - private final long getDisplayEDTHandle() { - return ((DisplayDriver) getScreen().getDisplay()).getEDTHandle(); - } - private final T runWithLockedDisplayHandle(DisplayRunnable action) { - return ((DisplayImpl) getScreen().getDisplay()).runWithLockedDisplayHandle(action); - // return runWithTempDisplayHandle(action); + private final T runWithLockedDisplayDevice(DisplayRunnable action) { + return ((DisplayDriver) getScreen().getDisplay()).runWithLockedDisplayDevice(action); } protected static native boolean initIDs0(); @@ -258,4 +300,5 @@ public class WindowDriver extends WindowImpl { private static native void warpPointer0(long display, long windowHandle, int x, int y); private long windowHandleClose; + private AbstractGraphicsDevice renderDevice; } diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h index 128b6b6f1..4d1a7b59e 100644 --- a/src/newt/native/X11Common.h +++ b/src/newt/native/X11Common.h @@ -70,7 +70,6 @@ extern jclass X11NewtWindowClazz; extern jmethodID insetsChangedID; extern jmethodID visibleChangedID; -void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 84b3a7630..56c11fab4 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -52,90 +52,6 @@ static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID requestFocusID = NULL; -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; - -static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } - jvmVersion = (*env)->GetVersion(env); -} - -static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerQuiet = 0 ; -static int errorHandlerDebug = 0 ; -static int errorHandlerThrowException = 0; - -static int x11ErrorHandler(Display *dpy, XErrorEvent *e) -{ - if(!errorHandlerQuiet) { - const char * errnoStr = strerror(errno); - char threadName[80]; - char errCodeStr[80]; - char reqCodeStr[80]; - - int shallBeDetached = 0; - JNIEnv *jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - - (void) NewtCommon_GetStaticStringMethod(jniEnv, X11NewtWindowClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); - XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); - XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); - - fprintf(stderr, "Info: Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - - if( errorHandlerDebug ) { - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11NewtWindowClazz, dumpStackID); - } - - if(errorHandlerThrowException) { - if(NULL != jniEnv) { - NewtCommon_throwNewRuntimeException(jniEnv, "Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - } else { - fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); - #if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } - #endif - } - } - fflush(stderr); - - if (NULL != jniEnv && shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } - } - - return 0; -} - -void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { - errorHandlerQuiet = quiet; - if(onoff) { - if(NULL==origErrorHandler) { - setupJVMVars(env); - origErrorHandler = XSetErrorHandler(x11ErrorHandler); - if(sync && NULL!=dpy) { - XSync(dpy, False); - } - } - } else { - if(NULL!=origErrorHandler) { - if(sync && NULL!=dpy) { - XSync(dpy, False); - } - XSetErrorHandler(origErrorHandler); - origErrorHandler = NULL; - } - } -} - /** * Keycode */ @@ -273,9 +189,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 { jclass c; - if(debug) { - errorHandlerDebug = 1 ; - } NewtCommon_init(env); if(NULL==X11NewtWindowClazz) { @@ -439,8 +352,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, #ifdef VERBOSE_ON True @@ -449,8 +360,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage #endif ); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - if(NULL==jwindow) { fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)dpy, evt.type, (void*)evt.xany.window); diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 59862f463..2e16e7cae 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -683,16 +683,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 DBG_PRINT( "X11: CloseWindow START dpy %p, win %p\n", (void*)dpy, (void*)w); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom, True); if(NULL==jwindow) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "could not fetch Java Window object, bail out!"); return; } if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "Internal Error .. Window global ref not the same!"); return; } @@ -700,7 +696,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 XSync(dpy, False); XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); // Drain all events related to this window .. Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom); @@ -761,8 +756,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo fsEWMHFlags |= _NET_WM_ABOVE; // toggle above } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - DBG_PRINT( "X11: reconfigureWindow0 dpy %p, scrn %d, parent %p/%p, win %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d, tempInvisible %d, fsEWMHFlags %d\n", (void*)dpy, screen_index, (void*) jparent, (void*)parent, (void*)w, x, y, width, height, @@ -779,7 +772,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo ( TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) ) { Bool enable = TST_FLAG_CHANGE_FULLSCREEN(flags) ? TST_FLAG_IS_FULLSCREEN(flags) : TST_FLAG_IS_ALWAYSONTOP(flags) ; if( NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, enable) ) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); #ifdef FS_GRAB_KEYBOARD if(TST_FLAG_CHANGE_FULLSCREEN(flags)) { if(TST_FLAG_IS_FULLSCREEN(flags)) { @@ -863,8 +855,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo #endif } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - DBG_PRINT( "X11: reconfigureWindow0 X\n"); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java new file mode 100644 index 000000000..11d1331ed --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java @@ -0,0 +1,219 @@ +/** + * Copyright 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: + * + * 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 com.jogamp.opengl.test.junit.jogl.acore; + +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.BeforeClass; + +import com.jogamp.newt.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +/** + * Concurrent and lock-free initialization and rendering using exclusive NEWT Display EDT instances, or + * concurrent locked initialization and lock-free rendering using a shared NEWT Display EDT instances. + *

+ * Rendering is always lock-free and independent of the EDT. + *

+ */ +public class InitConcurrentBaseNEWT extends UITestCase { + + static final int demoSize = 128; + + static long duration = 300; // ms + + static InsetsImmutable insets = null; + static int scrnHeight, scrnWidth; + static int num_x, num_y; + + @BeforeClass + public static void initClass() { + Window dummyWindow = NewtFactory.createWindow(new Capabilities()); + dummyWindow.setSize(demoSize, demoSize); + dummyWindow.setVisible(true); + Assert.assertEquals(true, dummyWindow.isVisible()); + Assert.assertEquals(true, dummyWindow.isNativeValid()); + insets = dummyWindow.getInsets(); + scrnHeight = dummyWindow.getScreen().getHeight(); + scrnWidth = dummyWindow.getScreen().getWidth(); + num_x = scrnWidth / ( demoSize + insets.getTotalWidth() ) - 2; + num_y = scrnHeight / ( demoSize + insets.getTotalHeight() ) - 2; + dummyWindow.destroy(); + } + + public class JOGLTask implements Runnable { + private final int id; + private final Object postSync; + private final boolean reuse; + private boolean done = false; + + public JOGLTask(Object postSync, int id, boolean reuse) { + this.postSync = postSync; + this.id = id; + this.reuse = reuse; + } + public void run() { + int x = ( id % num_x ) * ( demoSize + insets.getTotalHeight() ); + int y = ( (id / num_x) % num_y ) * ( demoSize + insets.getTotalHeight() ); + + System.err.println("JOGLTask "+id+": START: "+x+"/"+y+", reuse "+reuse+" - "+Thread.currentThread().getName()); + final Display display = NewtFactory.createDisplay(null, reuse); + final Screen screen = NewtFactory.createScreen(display, 0); + final GLWindow glWindow = GLWindow.create(screen, new GLCapabilities(GLProfile.getDefault())); + Assert.assertNotNull(glWindow); + glWindow.setTitle("Task "+id); + glWindow.setPosition(x + insets.getLeftWidth(), y + insets.getTopHeight() ); + + glWindow.addGLEventListener(new GearsES2(0)); + + Animator animator = new Animator(glWindow); + + glWindow.setSize(demoSize, demoSize); + glWindow.setVisible(true); + animator.setUpdateFPSFrames(60, null); + + System.err.println("JOGLTask "+id+": INITIALIZED: "+", "+display+" - "+Thread.currentThread().getName()); + + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(true, glWindow.isVisible()); + Assert.assertEquals(true, glWindow.isNativeValid()); + Assert.assertEquals(true, glWindow.isRealized()); + System.err.println("JOGLTask "+id+": RUNNING: "+Thread.currentThread().getName()); + + while(animator.isAnimating() && animator.getTotalFPSDuration()=0; i--) { + if(!tasks[i].done()) { + return false; + } + } + return true; + } + protected static String doneDump(JOGLTask[] tasks) { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for(int i=0; i0) { + sb.append(", "); + } + sb.append(i).append(": ").append(tasks[i].done()); + } + sb.append("]"); + return sb.toString(); + } + + protected static boolean isDead(Thread[] threads) { + for(int i=threads.length-1; i>=0; i--) { + if(threads[i].isAlive()) { + return false; + } + } + return true; + } + protected static String isAliveDump(Thread[] threads) { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for(int i=0; i0) { + sb.append(", "); + } + sb.append(i).append(": ").append(threads[i].isAlive()); + } + sb.append("]"); + return sb.toString(); + } + + protected void runJOGLTasks(int num, boolean reuse) throws InterruptedException { + final String currentThreadName = Thread.currentThread().getName(); + final Object syncDone = new Object(); + final JOGLTask[] tasks = new JOGLTask[num]; + final Thread[] threads = new Thread[num]; + int i; + for(i=0; i + * Rendering is always lock-free and independent of the EDT, however shared NEWT Display instances + * perform lifecycle actions (window creation etc) with locking. + *

+ */ +public class TestInitConcurrent01NEWT extends InitConcurrentBaseNEWT { + + @Test + public void test02TwoThreads() throws InterruptedException { + runJOGLTasks(2, true); + } + + @Test + public void test02FourThreads() throws InterruptedException { + runJOGLTasks(4, true); + } + + @Test + public void test16SixteenThreads() throws InterruptedException { + if( Platform.getCPUFamily() != Platform.CPUFamily.ARM ) { + runJOGLTasks(16, true); + } else { + runJOGLTasks( 8, true); + } + } + + public static void main(String args[]) throws IOException { + for(int i=0; i + * Rendering is always lock-free and independent of the EDT, however exclusive NEWT Display instances + * perform lifecycle actions (window creation etc) w/o locking. + *

+ */ +public class TestInitConcurrent02NEWT extends InitConcurrentBaseNEWT { + + @Test + public void test02TwoThreads() throws InterruptedException { + runJOGLTasks(2, false); + } + + @Test + public void test02FourThreads() throws InterruptedException { + runJOGLTasks(4, false); + } + + @Test + public void test16SixteenThreads() throws InterruptedException { + if( Platform.getCPUFamily() != Platform.CPUFamily.ARM ) { + runJOGLTasks(16, false); + } else { + runJOGLTasks( 8, false); + } + } + + public static void main(String args[]) throws IOException { + for(int i=0; i=0; i--) { - if(!tasks[i].done()) { - return false; - } - } - return true; - } - protected static String doneDump(JOGLTask[] tasks) { - StringBuilder sb = new StringBuilder(); - sb.append("["); - for(int i=0; i0) { - sb.append(", "); - } - sb.append(i).append(": ").append(tasks[i].done()); - } - sb.append("]"); - return sb.toString(); - } - - protected static boolean isDead(Thread[] threads) { - for(int i=threads.length-1; i>=0; i--) { - if(threads[i].isAlive()) { - return false; - } - } - return true; - } - protected static String isAliveDump(Thread[] threads) { - StringBuilder sb = new StringBuilder(); - sb.append("["); - for(int i=0; i0) { - sb.append(", "); - } - sb.append(i).append(": ").append(threads[i].isAlive()); - } - sb.append("]"); - return sb.toString(); - } - - protected void runJOGLTasks(int num) throws InterruptedException { - final String currentThreadName = Thread.currentThread().getName(); - final Object sync = new Object(); - final JOGLTask[] tasks = new JOGLTask[num]; - final Thread[] threads = new Thread[num]; - int i; - for(i=0; i Date: Fri, 28 Sep 2012 18:55:09 +0200 Subject: X11 NativeWindow: Fix Error and IOError handler, i.e. NPE checks and no JVM dependency (signal is async); X11Util: XSync w/ discard reusable Display when queue-in. --- .../classes/jogamp/nativewindow/x11/X11Util.java | 1 + src/nativewindow/native/x11/Xmisc.c | 73 ++++++++++------------ 2 files changed, 35 insertions(+), 39 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 60f54eb3c..67508bf87 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -425,6 +425,7 @@ public class X11Util { pendingDisplayList.remove(namedDpy); } else { // for reuse + X11Lib.XSync(namedDpy.getHandle(), true); // flush output buffer and discard all events reusableDisplayList.add(namedDpy); } diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index afdd413eb..9e2130668 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -160,10 +160,12 @@ static JavaVM *jvmHandle = NULL; static int jvmVersion = 0; static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + if( NULL != env && NULL == jvmHandle ) { + if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { + jvmHandle = NULL; + } + jvmVersion = (*env)->GetVersion(env); } - jvmVersion = (*env)->GetVersion(env); } static XErrorHandler origErrorHandler = NULL ; @@ -175,47 +177,42 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { if(!errorHandlerQuiet) { const char * errnoStr = strerror(errno); - char threadName[80]; char errCodeStr[80]; char reqCodeStr[80]; int shallBeDetached = 0; JNIEnv *jniEnv = NULL; - if( errorHandlerDebug || errorHandlerThrowException ) { - jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - } - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); - fprintf(stderr, "Info: Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + fprintf(stderr, "Info: Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); + fflush(stderr); - if( errorHandlerDebug && NULL != jniEnv ) { - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + if( NULL != jvmHandle && ( errorHandlerDebug || errorHandlerThrowException ) ) { + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if(NULL == jniEnv) { + fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); + fflush(stderr); + } } - if(errorHandlerThrowException) { - if(NULL != jniEnv) { - NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + if( NULL != jniEnv ) { + if( errorHandlerDebug ) { + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + } + + if(errorHandlerThrowException) { + NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); - } else { - fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); - #if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } - #endif } - } - fflush(stderr); - if (NULL != jniEnv && shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } } @@ -253,17 +250,15 @@ static int x11IOErrorHandler(Display *dpy) JNIEnv *jniEnv = NULL; fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr); - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); - - jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - if (NULL != jniEnv) { - char threadName[80]; - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - - NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); - - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); + fflush(stderr); + + if( NULL != jvmHandle ) { + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if (NULL != jniEnv) { + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr); + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } } if(NULL!=origIOErrorHandler) { -- cgit v1.2.3 From 92398025abdabb2fdef0d78edd41e730991a6f94 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 30 Sep 2012 19:47:46 +0200 Subject: Workaround for Bug 623: Sporadic XCB assertion failures w/ ATI proprietary driver and w/o native X11 locking The proprietary ATI X11 driver does not handle multi-threaded [GL] clients well, i.e. triggers an XCB assertion 'from time to time'. It almost seems like that the driver either: - aliases all display connections to it's connection name, i.e. server; or - utilizes a build-in display connection w/o locking, used for some reason +++ - X11Lib: Add QueryExtension(dpy, name) allowing early driver determination w/o GL - X11Util detects 'requiresGlobalToolkitLock' and 'markAllDisplaysUnclosable' via X11 extensions. In case certain ATI extensions are available, both are set to true. - X11GLXDrawableFactory: Dropped setting 'markAllDisplaysUnclosable', using X11Util's detection (see above). - New GlobalToolkitLock to satisfy certain driver restrictions (ATI's XCB multithreading bug) - NativeWindowFactory handles new property requiresGlobalToolkitLock, in which case the new GlobalToolkitLock is being used instead of ResourceToolkitLock. - JAWTUtil ToolkitLock locks GlobalToolkitLock 1st to match new 'requiresGlobalToolkitLock' property. - Document static method requirement of X11Util, GDIUtil and OSXUtil via marker interface ToolkitProperties - ToolkitLock: New method 'validateLocked()', allowing use to validate whether the device/toolkit is properly locked and hence to detect implementation bugs. See unit test class: ValidateLockListener --- make/config/nativewindow/x11-CustomJavaCode.java | 5 + make/scripts/tests.sh | 8 +- .../opengl/x11/glx/X11GLXDrawableFactory.java | 4 - .../jogamp/nativewindow/x11/X11GraphicsDevice.java | 2 +- .../media/nativewindow/AbstractGraphicsDevice.java | 11 ++- .../media/nativewindow/DefaultGraphicsDevice.java | 21 +++-- .../media/nativewindow/NativeWindowFactory.java | 101 +++++++++++++-------- .../javax/media/nativewindow/ToolkitLock.java | 22 ++++- .../jogamp/nativewindow/GlobalToolkitLock.java | 75 +++++++++++++++ .../nativewindow/NativeWindowFactoryImpl.java | 7 +- .../jogamp/nativewindow/NullToolkitLock.java | 19 +++- .../jogamp/nativewindow/ResourceToolkitLock.java | 15 ++- .../nativewindow/SharedResourceToolkitLock.java | 11 ++- .../jogamp/nativewindow/ToolkitProperties.java | 51 +++++++++++ .../classes/jogamp/nativewindow/jawt/JAWTUtil.java | 36 +++++++- .../jogamp/nativewindow/macosx/OSXUtil.java | 22 +++-- .../jogamp/nativewindow/windows/GDIUtil.java | 15 ++- .../classes/jogamp/nativewindow/x11/X11Util.java | 51 ++++++++--- src/nativewindow/native/x11/Xmisc.c | 35 +++++++ .../junit/jogl/acore/InitConcurrentBaseNEWT.java | 2 + .../test/junit/util/ValidateLockListener.java | 71 +++++++++++++++ 21 files changed, 496 insertions(+), 88 deletions(-) create mode 100644 src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java create mode 100644 src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java create mode 100644 src/test/com/jogamp/opengl/test/junit/util/ValidateLockListener.java (limited to 'src/nativewindow/native/x11') diff --git a/make/config/nativewindow/x11-CustomJavaCode.java b/make/config/nativewindow/x11-CustomJavaCode.java index 56aec4725..8e5da3b2d 100644 --- a/make/config/nativewindow/x11-CustomJavaCode.java +++ b/make/config/nativewindow/x11-CustomJavaCode.java @@ -36,6 +36,11 @@ } private static native Object GetRelativeLocation0(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y); + public static boolean QueryExtension(long display, String extensionName) { + return QueryExtension0(display, extensionName); + } + private static native boolean QueryExtension0(long display, String extensionName); + public static native int XCloseDisplay(long display); public static native void XUnlockDisplay(long display); public static native void XLockDisplay(long display); diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 345e23ae7..0908ef1fd 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -137,7 +137,8 @@ function jrun() { #D_ARGS="-Dnativewindow.debug=all" #D_ARGS="-Djogl.debug.GLCanvas" #D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.X11Util.XSync" - #D_ARGS="-Dnativewindow.debug.X11Util.XSync" + #D_ARGS="-Dnativewindow.debug.X11Util.XSync -Dnativewindow.debug.ToolkitLock.TraceLock" + D_ARGS="-Dnativewindow.debug.X11Util -Dnativewindow.debug.X11Util.XSync -Dnativewindow.debug.NullToolkitLock.InvalidLocked -Dnativewindow.debug.NativeWindow" #D_ARGS="-Dnativewindow.debug.ToolkitLock" #D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLCode -Djogl.debug.TraceGL" #D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLState" @@ -245,7 +246,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent01NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent02NEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent02NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextSurfaceLockNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT $* @@ -254,7 +255,8 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT $* -testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestBug623ATIXCBAssertionFailureNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $* diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index b867125ad..018f6a6ea 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -241,10 +241,6 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { final String glXServerVendorName = GLX.glXQueryServerString(sharedDevice.getHandle(), 0, GLX.GLX_VENDOR); final VersionNumber glXServerVersion = GLXUtil.getGLXServerVersionNumber(sharedDevice); final boolean glXServerMultisampleAvailable = GLXUtil.isMultisampleAvailable(GLX.glXQueryServerString(sharedDevice.getHandle(), 0, GLX.GLX_EXTENSIONS)); - if(X11Util.ATI_HAS_XCLOSEDISPLAY_BUG && GLXUtil.isVendorATI(glXServerVendorName)) { - X11Util.setMarkAllDisplaysUnclosable(true); - X11Util.markDisplayUncloseable(sharedDevice.getHandle()); - } final GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP, false); if (null == glp) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java index 142bb99e3..0f28ca67c 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java @@ -61,7 +61,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } /** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default - * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long) */ public X11GraphicsDevice(long display, int unitID, boolean owner) { diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 5eaaa6613..8ecd5242d 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -102,17 +102,24 @@ public interface AbstractGraphicsDevice extends Cloneable { public long getHandle(); /** - * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}. + * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock#lock()}. * The lock implementation must be recursive. */ public void lock(); /** - * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}. + * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock#unlock()}. * The lock implementation must be recursive. + * + * @throws RuntimeException in case the lock is not acquired by this thread. */ public void unlock(); + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + /** * Optionally [re]opening the device if handle is null. *

diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index b16b0c75c..9288652d9 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -60,7 +60,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice /** * Create an instance with the system default {@link ToolkitLock}. - * gathered via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. * @param type * @param handle */ @@ -70,7 +70,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = handle; - this.toolkitLock = NativeWindowFactory.createDefaultToolkitLock(type, handle); + this.toolkitLock = NativeWindowFactory.getDefaultToolkitLock(type, handle); } /** @@ -123,8 +123,10 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } /** - * No lock is performed on the graphics device per default, - * instead the aggregated recursive {@link ToolkitLock#lock()} is invoked. + * {@inheritDoc} + *

+ * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}. + *

* * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) @@ -134,9 +136,16 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice toolkitLock.lock(); } + @Override + public final void validateLocked() throws RuntimeException { + toolkitLock.validateLocked(); + } + /** - * No lock is performed on the graphics device per default, - * instead the aggregated recursive {@link ToolkitLock#unlock()} is invoked. + * {@inheritDoc} + *

+ * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}. + *

* * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index 4f4bb629b..af8008f0f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -42,6 +42,7 @@ import java.util.Map; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NativeWindowFactoryImpl; +import jogamp.nativewindow.ToolkitProperties; import jogamp.nativewindow.ResourceToolkitLock; import com.jogamp.common.os.Platform; @@ -87,13 +88,17 @@ public abstract class NativeWindowFactory { private static boolean isAWTAvailable; 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.macosx.OSXUtil} implements {@link ToolkitProperties}. */ private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; + /** {@link jogamp.nativewindow.windows.GDIUtil} implements {@link ToolkitProperties}. */ private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; private static ToolkitLock jawtUtilJAWTToolkitLock; private static boolean requiresToolkitLock; + private static boolean requiresGlobalToolkitLock; private static volatile boolean isJVMShuttingDown = false; @@ -156,11 +161,18 @@ public abstract class NativeWindowFactory { if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "initSingleton", null, null, cl ); - final Boolean res = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl); - requiresToolkitLock = res.booleanValue(); + final Boolean res1 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl); + requiresToolkitLock = res1.booleanValue(); + if(requiresToolkitLock) { + final Boolean res2 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresGlobalToolkitLock", null, null, cl); + requiresGlobalToolkitLock = res2.booleanValue(); + } else { + requiresGlobalToolkitLock = false; + } } else { requiresToolkitLock = false; - } + requiresGlobalToolkitLock = false; + } } private static void shutdownNativeImpl(final ClassLoader cl) { @@ -261,7 +273,7 @@ public abstract class NativeWindowFactory { } if(DEBUG) { - System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock); + System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock+", requiresGlobalToolkitLock "+requiresGlobalToolkitLock); System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory); } @@ -295,7 +307,12 @@ public abstract class NativeWindowFactory { /** @return true if the underlying toolkit requires locking, otherwise false. */ public static boolean requiresToolkitLock() { return requiresToolkitLock; - } + } + + /** @return true if the underlying toolkit requires global locking, otherwise false. */ + public static boolean requiresGlobalToolkitLock() { + return requiresGlobalToolkitLock; + } /** @return true if not headless, AWT Component and NativeWindow's AWT part available */ public static boolean isAWTAvailable() { return isAWTAvailable; } @@ -331,9 +348,28 @@ public abstract class NativeWindowFactory { return defaultFactory; } + /** + * Returns the AWT {@link ToolkitLock} (JAWT based) if {@link #isAWTAvailable}, otherwise null. + *

+ * The JAWT based {@link ToolkitLock} also locks the global lock, + * which matters if the latter is required. + *

+ */ + public static ToolkitLock getAWTToolkitLock() { + return jawtUtilJAWTToolkitLock; + } + + public static ToolkitLock getNullToolkitLock() { + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + public static ToolkitLock getGlobalToolkitLock() { + return NativeWindowFactoryImpl.getGlobalToolkitLock(); + } + /** - * Provides the system default {@link ToolkitLock}, a singleton instance. - *
+ * Provides the system default {@link ToolkitLock} for the default system windowing type. + * @see #getNativeWindowType(boolean) * @see #getDefaultToolkitLock(java.lang.String) */ public static ToolkitLock getDefaultToolkitLock() { @@ -341,57 +377,44 @@ public abstract class NativeWindowFactory { } /** - * Provides the default {@link ToolkitLock} for type, a singleton instance. + * Provides the default {@link ToolkitLock} for type. *
    - *
  • JAWT {@link ToolkitLock} if required and AWT available, otherwise
  • + *
  • JAWT {@link ToolkitLock} if required and type is of {@link #TYPE_AWT} and AWT available,
  • + *
  • {@link jogamp.nativewindow.GlobalToolkitLock} if required, otherwise
  • + *
  • {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise
  • *
  • {@link jogamp.nativewindow.NullToolkitLock}
  • *
*/ public static ToolkitLock getDefaultToolkitLock(String type) { - if( requiresToolkitLock() ) { - if( TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) && isAWTAvailable() ) { + if( requiresToolkitLock ) { + if( TYPE_AWT == type && isAWTAvailable() ) { return getAWTToolkitLock(); } - } - return NativeWindowFactoryImpl.getNullToolkitLock(); - } - - /** Returns the AWT Toolkit (JAWT based) if {@link #isAWTAvailable}, otherwise null. */ - public static ToolkitLock getAWTToolkitLock() { - return jawtUtilJAWTToolkitLock; - } - - public static ToolkitLock getNullToolkitLock() { - return NativeWindowFactoryImpl.getNullToolkitLock(); - } - - /** - * Creates the default {@link ToolkitLock} for type and deviceHandle. - *
    - *
  • {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise
  • - *
  • {@link jogamp.nativewindow.NullToolkitLock}
  • - *
- */ - public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { - if( requiresToolkitLock() ) { + if( requiresGlobalToolkitLock ) { + return NativeWindowFactoryImpl.getGlobalToolkitLock(); + } return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } - + /** - * Creates the default {@link ToolkitLock} for type and deviceHandle. + * Provides the default {@link ToolkitLock} for type and deviceHandle. *
    - *
  • JAWT {@link ToolkitLock} if required and AWT available,
  • + *
  • JAWT {@link ToolkitLock} if required and type is of {@link #TYPE_AWT} and AWT available,
  • + *
  • {@link jogamp.nativewindow.GlobalToolkitLock} if required, otherwise
  • *
  • {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise
  • *
  • {@link jogamp.nativewindow.NullToolkitLock}
  • *
*/ - public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) { - if( requiresToolkitLock() ) { - if( TYPE_AWT == sharedType && isAWTAvailable() ) { + public static ToolkitLock getDefaultToolkitLock(String type, long deviceHandle) { + if( requiresToolkitLock ) { + if( TYPE_AWT == type && isAWTAvailable() ) { return getAWTToolkitLock(); } + if( requiresGlobalToolkitLock ) { + return NativeWindowFactoryImpl.getGlobalToolkitLock(); + } return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java index 18b7cf5d9..eccfcfa4f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java @@ -37,15 +37,35 @@ import jogamp.nativewindow.Debug; * Toolkit locks are created solely via {@link NativeWindowFactory}. *

*

- * One use case is the AWT locking on X11, see {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * One use case is the AWT locking on X11, see {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. *

*/ public interface ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true); + /** + * Blocking until the lock is acquired by this Thread or a timeout is reached. + *

+ * Timeout is implementation specific, if used at all. + *

+ * + * @throws RuntimeException in case of a timeout + */ public void lock(); + + /** + * Release the lock. + * + * @throws RuntimeException in case the lock is not acquired by this thread. + */ public void unlock(); + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + /** * Dispose this instance. *

diff --git a/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java new file mode 100644 index 000000000..0c2a1e43f --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java @@ -0,0 +1,75 @@ +/** + * Copyright 2012 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; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a global recursive {@link javax.media.nativewindow.ToolkitLock}. + *

+ * This is the last resort for unstable driver, e.g. proprietary ATI/X11 12.8 and 12.9, + * where multiple X11 display connections to the same connection name are not treated + * thread safe within the GL/X11 driver. + *

+ */ +public class GlobalToolkitLock implements ToolkitLock { + private static final RecursiveLock globalLock = LockFactory.createRecursiveLock(); + + /** Singleton via {@link NativeWindowFactoryImpl#getGlobalToolkitLock()} */ + protected GlobalToolkitLock() { } + + @Override + public final void lock() { + globalLock.lock(); + if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.lock()"); } + } + + @Override + public final void unlock() { + if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.unlock()"); } + globalLock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + globalLock.validateLocked(); + } + + @Override + public final void dispose() { + // nop + } + + public String toString() { + return "GlobalToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+globalLock.isOwner(Thread.currentThread())+", "+globalLock.toString()+"]"; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index 29564da3b..c35cede77 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -44,9 +44,14 @@ import com.jogamp.common.util.ReflectionUtil.AWTNames; public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); + private static final ToolkitLock globalToolkitLock = new GlobalToolkitLock(); public static ToolkitLock getNullToolkitLock() { - return nullToolkitLock; + return nullToolkitLock; + } + + public static ToolkitLock getGlobalToolkitLock() { + return globalToolkitLock; } // This subclass of NativeWindowFactory handles the case of diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java index e59910138..211e15955 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java @@ -31,15 +31,16 @@ package jogamp.nativewindow; import javax.media.nativewindow.ToolkitLock; /** - * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock} - * without any locking. Since there is no locking it all, - * it is intrinsically recursive. + * Implementing a singleton global NOP {@link javax.media.nativewindow.ToolkitLock} + * without any locking. Since there is no locking it all, it is intrinsically recursive. */ public class NullToolkitLock implements ToolkitLock { - + public static final boolean INVALID_LOCKED = Debug.isPropertyDefined("nativewindow.debug.NullToolkitLock.InvalidLocked", true); + /** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */ protected NullToolkitLock() { } + @Override public final void lock() { if(TRACE_LOCK) { System.err.println("NullToolkitLock.lock()"); @@ -47,10 +48,20 @@ public class NullToolkitLock implements ToolkitLock { } } + @Override public final void unlock() { if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } } + @Override + public final void validateLocked() throws RuntimeException { + /* nop */ + if(INVALID_LOCKED) { + throw new RuntimeException("NullToolkitLock does not lock"); + } + } + + @Override public final void dispose() { // nop } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java index a3b0804fa..5b79de0b8 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java @@ -41,8 +41,6 @@ import com.jogamp.common.util.locks.RecursiveLock; *

*/ public class ResourceToolkitLock implements ToolkitLock { - public static final boolean DEBUG = Debug.debug("ToolkitLock"); - public static final ResourceToolkitLock create() { return new ResourceToolkitLock(); } @@ -53,17 +51,24 @@ public class ResourceToolkitLock implements ToolkitLock { this.lock = LockFactory.createRecursiveLock(); } - + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); } lock.lock(); + if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); } } + @Override public final void unlock() { if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.unlock()"); } - lock.unlock(); + lock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); } + @Override public final void dispose() { // nop } diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java index 5d7ae8abb..94d12e6fc 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -49,7 +49,6 @@ import com.jogamp.common.util.locks.RecursiveLock; *

*/ public class SharedResourceToolkitLock implements ToolkitLock { - public static final boolean DEBUG = Debug.debug("ToolkitLock"); private static final LongObjectHashMap handle2Lock; static { handle2Lock = new LongObjectHashMap(); @@ -109,16 +108,24 @@ public class SharedResourceToolkitLock implements ToolkitLock { } + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); } lock.lock(); + if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); } } + @Override public final void unlock() { if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.unlock()"); } lock.unlock(); } + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); + } + + @Override public final void dispose() { if(0 < refCount) { // volatile OK synchronized(handle2Lock) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java new file mode 100644 index 000000000..2062d1f58 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java @@ -0,0 +1,51 @@ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; + +/** + * Marker interface. + *

+ * Implementation requires to provide static methods: + *

+    public static void initSingleton() {}
+    
+    public static void shutdown() {}
+    
+    public static boolean requiresToolkitLock() {}
+    
+    public static boolean requiresGlobalToolkitLock() {}
+ * 
+ * Above static methods are invoked by {@link NativeWindowFactory#initSingleton()}, + * or {@link NativeWindowFactory#shutdown()} via reflection. + *

+ *

+ * If requiresGlobalToolkitLock() == true, then + * requiresToolkitLock() == true shall be valid as well. + *

+ */ +public interface ToolkitProperties { + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // void initSingleton(); + + /** + * Cleanup resources. + *

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

+ */ + // void shutdown(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean requiresToolkitLock(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean requiresGlobalToolkitLock(); + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index 7c934b154..2dadfb16b 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -79,6 +79,8 @@ public class JAWTUtil { private static final Method sunToolkitAWTLockMethod; private static final Method sunToolkitAWTUnlockMethod; private static final boolean hasSunToolkitAWTLock; + + private static volatile Thread exclusiveOwnerThread; private static final ToolkitLock jawtToolkitLock; @@ -229,13 +231,23 @@ public class JAWTUtil { } hasSunToolkitAWTLock = _hasSunToolkitAWTLock; // hasSunToolkitAWTLock = false; + exclusiveOwnerThread = null; jawtToolkitLock = new ToolkitLock() { public final void lock() { + NativeWindowFactory.getGlobalToolkitLock().lock(); JAWTUtil.lockToolkit(); + if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.lock()"); } } public final void unlock() { + if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.unlock()"); } JAWTUtil.unlockToolkit(); + NativeWindowFactory.getGlobalToolkitLock().unlock(); + } + @Override + public final void validateLocked() throws RuntimeException { + NativeWindowFactory.getGlobalToolkitLock().validateLocked(); + JAWTUtil.validateLocked(); } public final void dispose() { // nop @@ -312,7 +324,7 @@ public class JAWTUtil { * JAWT's native Lock() function calls SunToolkit.awtLock(), * which just uses AWT's global ReentrantLock.
*/ - private static void awtLock() { + private static final void awtLock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTLockMethod.invoke(null, (Object[])null); @@ -322,6 +334,7 @@ public class JAWTUtil { } else { jawtLockObject.Lock(); } + exclusiveOwnerThread = Thread.currentThread(); } /** @@ -330,7 +343,9 @@ public class JAWTUtil { * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), * which just uses AWT's global ReentrantLock.
*/ - private static void awtUnlock() { + private static final void awtUnlock() { + awtValidateLocked(); + exclusiveOwnerThread = null; if(hasSunToolkitAWTLock) { try { sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); @@ -342,6 +357,16 @@ public class JAWTUtil { } } + private static final void awtValidateLocked() throws RuntimeException { + final Thread ct = Thread.currentThread(); + if( ct != exclusiveOwnerThread ) { + if ( null == exclusiveOwnerThread ) { + throw new RuntimeException(ct.getName()+": JAWT-ToolkitLock not locked"); + } + throw new RuntimeException(ct.getName()+": Not JAWT-ToolkitLock owner. Owner is "+exclusiveOwnerThread.getName()); + } + } + public static void lockToolkit() throws NativeWindowException { if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock()"); } if(!headlessMode && !isJava2DQueueFlusherThread()) { @@ -355,6 +380,13 @@ public class JAWTUtil { awtUnlock(); } } + + public static final void validateLocked() throws RuntimeException { + if(!headlessMode && !isJava2DQueueFlusherThread()) { + awtValidateLocked(); + } + } + public static ToolkitLock getJAWTToolkitLock() { return jawtToolkitLock; diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index b7a83e133..481cbbe39 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -34,13 +34,15 @@ import javax.media.nativewindow.util.Point; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; -public class OSXUtil { +public class OSXUtil implements ToolkitProperties { private static boolean isInit = false; private static final boolean DEBUG = Debug.debug("OSXUtil"); /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static synchronized void initSingleton() { if(!isInit) { @@ -60,13 +62,21 @@ public class OSXUtil { /** * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties */ - public static void shutdown() { - } + public static void shutdown() { } - public static boolean requiresToolkitLock() { - return false; - } + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static boolean requiresToolkitLock() { return false; } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean requiresGlobalToolkitLock() { return false; } public static boolean isNSView(long object) { return isNSView0(object); diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java index 613c76032..4408a0903 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -33,9 +33,10 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.Debug; +import jogamp.nativewindow.ToolkitProperties; import jogamp.nativewindow.x11.X11Util; -public class GDIUtil { +public class GDIUtil implements ToolkitProperties { private static final boolean DEBUG = Debug.debug("GDIUtil"); private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ; @@ -44,6 +45,7 @@ public class GDIUtil { /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static synchronized void initSingleton() { if(!isInit) { @@ -67,12 +69,23 @@ public class GDIUtil { /** * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties */ public static void shutdown() { } + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ public static boolean requiresToolkitLock() { return false; } + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean requiresGlobalToolkitLock() { return false; } + private static RegisteredClass dummyWindowClass = null; private static Object dummyWindowSync = new Object(); diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 30792113d..a331fa940 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -43,13 +43,15 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; + import com.jogamp.common.util.LongObjectHashMap; import com.jogamp.nativewindow.x11.X11GraphicsDevice; /** * Contains a thread safe X11 utility to retrieve display connections. */ -public class X11Util { +public class X11Util implements ToolkitProperties { /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 *

@@ -88,11 +90,15 @@ public class X11Util { private static String nullDisplayName = null; private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues + private static boolean requiresGlobalToolkitLock = false; // ATI/AMD X11 driver issues private static 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) { @@ -100,7 +106,7 @@ public class X11Util { if(!isInit) { isInit = true; if(DEBUG) { - System.out.println("X11UtilUtil.initSingleton()"); + System.out.println("X11Util.initSingleton()"); } if(!NWJNILibLoader.loadNativeWindow("x11")) { throw new NativeWindowException("NativeWindow X11 native library load error."); @@ -108,6 +114,7 @@ public class X11Util { final boolean isInitOK = initialize0( XERROR_STACKDUMP ); + final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION; final long dpy = X11Lib.XOpenDisplay(null); if(0 != dpy) { if(XSYNC_ENABLED) { @@ -115,17 +122,29 @@ public class X11Util { } 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; } + requiresGlobalToolkitLock = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION; + markAllDisplaysUnclosable = ATI_HAS_XCLOSEDISPLAY_BUG && ( hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION ); if(DEBUG) { - System.err.println("X11Util init OK "+isInitOK+"]"+ - ", X11 Display(NULL) <"+nullDisplayName+">"+ - ", XSynchronize Enabled: "+XSYNC_ENABLED); + 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 requiresGlobalToolkitLock "+requiresGlobalToolkitLock()+ + ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable() + ); // Thread.dumpStack(); } } @@ -147,6 +166,7 @@ public class X11Util { *

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

+ * @see ToolkitProperties */ public static void shutdown() { if(isInit) { @@ -189,8 +209,20 @@ public class X11Util { } } - public static boolean requiresToolkitLock() { - return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock. + /** + * 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 requiresGlobalToolkitLock() { + return requiresGlobalToolkitLock; // JAWT locking: yes, instead of native X11 locking w use a global lock. } public static void setX11ErrorHandler(boolean onoff, boolean quiet) { @@ -206,9 +238,6 @@ public class X11Util { public static boolean getMarkAllDisplaysUnclosable() { return markAllDisplaysUnclosable; } - public static void setMarkAllDisplaysUnclosable(boolean v) { - markAllDisplaysUnclosable = v; - } private X11Util() {} @@ -373,7 +402,7 @@ public class X11Util { name = validateDisplayName(name); boolean reused = false; - synchronized(globalLock) { + synchronized(globalLock) { for(int i=0; iNewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y); } +/* + * Class: jogamp_nativewindow_x11_X11Lib + * Method: QueryExtension0 + * Signature: (JLjava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Lib_QueryExtension0 + (JNIEnv *env, jclass unused, jlong jdisplay, jstring jextensionName) +{ + int32_t major_opcode, first_event, first_error; + jboolean res = JNI_FALSE; + Display * display = (Display *) (intptr_t) jdisplay; + const char* extensionName = NULL; + + if(NULL==display) { + NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"display\""); + return res; + } + if ( NULL == jextensionName ) { + NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"extensionName\""); + return res; + } + extensionName = (*env)->GetStringUTFChars(env, jextensionName, (jboolean*)NULL); + if ( NULL == extensionName ) { + NativewindowCommon_throwNewRuntimeException(env, "Failed to get UTF-8 chars for argument \"extensionName\""); + return res; + } + + res = True == XQueryExtension(display, extensionName, &major_opcode, &first_event, &first_error) ? JNI_TRUE : JNI_FALSE; + + if ( NULL != jextensionName ) { + (*env)->ReleaseStringUTFChars(env, jextensionName, extensionName); + } + return res; +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java index 11d1331ed..6b2de8366 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java @@ -43,6 +43,7 @@ import com.jogamp.newt.Window; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.test.junit.util.ValidateLockListener; import com.jogamp.opengl.util.Animator; /** @@ -100,6 +101,7 @@ public class InitConcurrentBaseNEWT extends UITestCase { glWindow.setTitle("Task "+id); glWindow.setPosition(x + insets.getLeftWidth(), y + insets.getTopHeight() ); + glWindow.addGLEventListener(new ValidateLockListener()); glWindow.addGLEventListener(new GearsES2(0)); Animator animator = new Animator(glWindow); diff --git a/src/test/com/jogamp/opengl/test/junit/util/ValidateLockListener.java b/src/test/com/jogamp/opengl/test/junit/util/ValidateLockListener.java new file mode 100644 index 000000000..73c1ad74c --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/util/ValidateLockListener.java @@ -0,0 +1,71 @@ +/** + * Copyright 2012 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 com.jogamp.opengl.test.junit.util; + + +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; + + +public class ValidateLockListener implements GLEventListener { + + private void validateLock(GLAutoDrawable drawable) { + final NativeSurface ns = drawable.getNativeSurface(); + ns.getGraphicsConfiguration().getScreen().getDevice().validateLocked(); + + final Thread current = Thread.currentThread(); + final Thread owner = ns.getSurfaceLockOwner(); + if( ns.isSurfaceLockedByOtherThread() ) { + throw new RuntimeException(current.getName()+": Locked by another thread(1), owner "+owner+", "+ns); + } + if( current != owner ) { + if( null == owner ) { + throw new RuntimeException(current.getName()+": Not locked: "+ns); + } + throw new RuntimeException(current.getName()+": Locked by another thread(2), owner "+owner+", "+ns); + } + } + + public void init(GLAutoDrawable drawable) { + validateLock(drawable); + } + + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + validateLock(drawable); + } + + public void display(GLAutoDrawable drawable) { + validateLock(drawable); + } + + public void dispose(GLAutoDrawable drawable) { + validateLock(drawable); + } +} -- cgit v1.2.3 From 21b85e647f1e661c8e5e49caa91c564a3d041df2 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 2 Oct 2012 07:29:13 +0200 Subject: Fix commit fbe331f013608eb31ff0d8675f4e4c9881c9c48b (Bug 616 - Remove XInitThreads()) X11Util/Native: Fix X11Util_initialize0() arguments were wrong and code still invoked XInitThreads() .. woops; Added missing included "jogamp_nativewindow_x11_X11Util.h" incl. it's generation via javah, which was the culprit of not detecting it at compile time. This is a fix for commit fbe331f013608eb31ff0d8675f4e4c9881c9c48b --- make/build-nativewindow.xml | 1 + src/nativewindow/native/x11/Xmisc.c | 22 +++++----------------- 2 files changed, 6 insertions(+), 17 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/make/build-nativewindow.xml b/make/build-nativewindow.xml index 6a9dbdc2e..3c97d9d9b 100644 --- a/make/build-nativewindow.xml +++ b/make/build-nativewindow.xml @@ -759,6 +759,7 @@ + NewGlobalRef(env, clazz); - if( JNI_TRUE == firstUIActionOnProcess ) { - if( 0 == XInitThreads() ) { - fprintf(stderr, "Warning: XInitThreads() failed\n"); - } else { - _xinitThreadsOK=JNI_TRUE; - if(debug) { - fprintf(stderr, "X11: XInitThreads() called for concurrent Thread support\n"); - } - } - } else if(debug) { - fprintf(stderr, "X11: XInitThreads() _not_ called for concurrent Thread support\n"); - } _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); @@ -310,7 +298,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo fprintf(stderr, "Info: NativeWindow native init passed\n"); } } - return _xinitThreadsOK; + return JNI_TRUE; } JNIEXPORT void JNICALL -- cgit v1.2.3 From 337ae7842fc9a78196dab9a21eb052b3f4dfc5cd Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 27 Nov 2012 19:03:57 +0100 Subject: X11Util/Xmisc setX11ErrorHandler: Force setting X11 error handler if invoked from Java ensuring to overwrite other TKs handler SWT sets it's error handler, which exits application in case of an X11 error (e.g. n/a GL3 impl.). We need to allow overwriting it, hence allowing multiple calls (NEWT, GLContext). This patch also makes native NativewindowCommon_x11ErrorHandlerEnable(..) function static. --- src/nativewindow/native/x11/Xmisc.c | 46 ++++++++++++++++++++----------------- src/nativewindow/native/x11/Xmisc.h | 2 -- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 129baac62..c73952693 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -220,12 +220,16 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) return 0; } -void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { +static void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int force, int onoff, int quiet, int sync) { errorHandlerQuiet = quiet; if(onoff) { - if(NULL==origErrorHandler) { + if(force || NULL==origErrorHandler) { + XErrorHandler prevErrorHandler; setupJVMVars(env); - origErrorHandler = XSetErrorHandler(x11ErrorHandler); + prevErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(x11ErrorHandler != prevErrorHandler) { // if forced don't overwrite w/ orig w/ our handler + origErrorHandler = prevErrorHandler; + } if(sync && NULL!=dpy) { XSync(dpy, False); } @@ -292,7 +296,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0 /* no dpy, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 1, 0, 0 /* no dpy, force, no sync */); _initialized=1; if(JNI_TRUE == debug) { fprintf(stderr, "Info: NativeWindow native init passed\n"); @@ -303,13 +307,13 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0 /* no dpy, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0, 0 /* no dpy, no sync */); x11IOErrorHandlerEnable(0, env); } JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _unused, jboolean onoff, jboolean quiet) { - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, force, no sync */); } /* Java->C glue code: @@ -334,9 +338,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja if (arg3 != NULL) { _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, 0, 0); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0, 0); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -363,7 +367,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u return; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 1); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 1); memset(&xwa, 0, sizeof(XWindowAttributes)); XGetWindowAttributes(dpy, w, &xwa); if(NULL != xwa.visual) { @@ -371,7 +375,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u } else { r = 0; } - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); return r; } @@ -383,9 +387,9 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 1, 0, 0); r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0, 0); return r; } @@ -426,9 +430,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 1, 0, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0, 0); return _res; } @@ -466,7 +470,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow return 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); @@ -486,7 +490,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -530,7 +534,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow XSelectInput(dpy, window, 0); // no events - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -554,11 +558,11 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow return; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); } /* @@ -582,11 +586,11 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio if( 0 == jdest_win ) { dest_win = root; } if( 0 == jsrc_win ) { src_win = root; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); diff --git a/src/nativewindow/native/x11/Xmisc.h b/src/nativewindow/native/x11/Xmisc.h index a44da950d..91f2ac5d9 100644 --- a/src/nativewindow/native/x11/Xmisc.h +++ b/src/nativewindow/native/x11/Xmisc.h @@ -39,6 +39,4 @@ #include #include -void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); - #endif /* Xmisc_h */ -- cgit v1.2.3 From 7cb6cf2a9708d3f4e06f2215eb0d06b00fa6cd15 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 4 Dec 2012 07:10:59 +0100 Subject: SWT GLCanvas: Fix sporadic drop of redraw on X11 _and_ allow using custom GLCapabilities on X11 (feature complete) To allow custom GLCapabilities, we had to use native parenting on X11 w/ a new child window. The desired visualID chosen by the users GLCapabilities is passed to the new child window. The redraw drops must be caused by the original GDK or the new child GDK window. Now we use a plain X11 child window similar to NEWT's X11 window and NewtCanvasSWT, which doesn't expose this bug. (Note: SWTAccessor/GLCanvas still contains the uncommented GDK code path for further inspection, if desired) Also added SWTNewtEventFactory to test event handling on the SWT GLCanvas w/ GearsES2. TestSWTJOGLGLCanvas01GLn tests custom GLCapabilities now. SWTEDTUtil has been moved to private: com.jogamp.newt.swt -> jogamp.newt.swt. --- make/build-common.xml | 1 + make/build-newt.xml | 2 +- make/config/nativewindow/x11-CustomJavaCode.java | 5 +- make/scripts/tests-x32.sh | 2 + make/scripts/tests-x64.bat | 4 +- make/scripts/tests.sh | 6 +- .../classes/com/jogamp/opengl/swt/GLCanvas.java | 350 ++++++++++++++------- .../com/jogamp/nativewindow/swt/SWTAccessor.java | 345 +++++++++++++------- .../x11/X11DummyUpstreamSurfaceHook.java | 4 +- src/nativewindow/native/x11/Xmisc.c | 123 +++++++- .../classes/com/jogamp/newt/swt/NewtCanvasSWT.java | 82 +++-- .../classes/com/jogamp/newt/swt/SWTEDTUtil.java | 313 ------------------ src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java | 313 ++++++++++++++++++ .../jogamp/newt/swt/event/SWTNewtEventFactory.java | 249 +++++++++++++++ .../opengl/test/junit/jogl/demos/es2/GearsES2.java | 8 +- .../swt/TestNewtCanvasSWTBug628ResizeDeadlock.java | 5 +- .../junit/jogl/swt/TestSWTBug643AsyncExec.java | 26 +- .../junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java | 16 +- 18 files changed, 1236 insertions(+), 618 deletions(-) delete mode 100644 src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java create mode 100644 src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java create mode 100644 src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java (limited to 'src/nativewindow/native/x11') diff --git a/make/build-common.xml b/make/build-common.xml index a718ae09a..414b0eba2 100644 --- a/make/build-common.xml +++ b/make/build-common.xml @@ -428,6 +428,7 @@ + diff --git a/make/build-newt.xml b/make/build-newt.xml index 7b9a51863..c3b51141f 100644 --- a/make/build-newt.xml +++ b/make/build-newt.xml @@ -112,7 +112,7 @@ value="com/jogamp/newt/awt/** com/jogamp/newt/event/awt/** jogamp/newt/awt/** ${java.part.driver.awt}"/> + value="com/jogamp/newt/swt/** jogamp/newt/swt/**"/> diff --git a/make/config/nativewindow/x11-CustomJavaCode.java b/make/config/nativewindow/x11-CustomJavaCode.java index 8e5da3b2d..4240c5e2f 100644 --- a/make/config/nativewindow/x11-CustomJavaCode.java +++ b/make/config/nativewindow/x11-CustomJavaCode.java @@ -28,8 +28,9 @@ public static native int DefaultVisualID(long display, int screen); - public static native long CreateDummyWindow(long display, int screen_index, int visualID, int width, int height); - public static native void DestroyDummyWindow(long display, long window); + public static native long CreateWindow(long parent, long display, int screen_index, int visualID, int width, int height, boolean input, boolean visible); + public static native void DestroyWindow(long display, long window); + public static native void SetWindowPosSize(long display, long window, int x, int y, int width, int height); public static Point GetRelativeLocation(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y) { return (Point) GetRelativeLocation0(display, screen_index, src_win, dest_win, src_x, src_y); diff --git a/make/scripts/tests-x32.sh b/make/scripts/tests-x32.sh index a3aed84c3..858ed5fd8 100755 --- a/make/scripts/tests-x32.sh +++ b/make/scripts/tests-x32.sh @@ -6,6 +6,8 @@ if [ -e $SDIR/../../../gluegen/make/scripts/setenv-build-jogl-x86.sh ] ; then . $SDIR/../../../gluegen/make/scripts/setenv-build-jogl-x86.sh fi +export SWT_CLASSPATH=`pwd`/lib/swt/gtk-linux-x86/swt-debug.jar + . $SDIR/tests.sh `which java` -d32 ../build-x86 $* diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat index 7a2946d31..db7e27264 100755 --- a/make/scripts/tests-x64.bat +++ b/make/scripts/tests-x64.bat @@ -54,10 +54,10 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestP REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn %* -REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %* +scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTBug628ResizeDeadlock %* -scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec %* +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestWindows01NEWT REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 0669efb37..628ab706b 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -113,7 +113,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile" #D_ARGS="-Djogl.debug.GLProfile" #D_ARGS="-Dnativewindow.debug.NativeWindow" - #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT" + D_ARGS="-Djogl.debug.GLCanvas -Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT -Djogl.debug.Animator" #D_ARGS="-Dnewt.debug.EDT -Dnewt.debug.Window -Djogl.debug.GLContext" #D_ARGS="-Dnativewindow.debug.X11Util.XErrorStackDump -Dnativewindow.debug.X11Util.TraceDisplayLifecycle -Dnativewindow.debug.X11Util" #D_ARGS="-Dnativewindow.debug.X11Util -Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnewt.debug=all" @@ -370,10 +370,10 @@ function testawtswt() { # #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTEclipseGLCanvas01GLn $* #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn $* -#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $* +testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $* #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn $* #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTBug628ResizeDeadlock $* -testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec $* +#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec $* # # newt.awt (testawt) diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index a080a7045..0320c63ae 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -29,10 +29,16 @@ package com.jogamp.opengl.swt; import java.util.List; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.nativewindow.VisualIDHolder; +import javax.media.nativewindow.VisualIDHolder.VIDType; import javax.media.opengl.GL; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; @@ -48,23 +54,20 @@ import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; import javax.media.opengl.Threading; +import jogamp.nativewindow.x11.X11Util; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableHelper; import jogamp.opengl.GLDrawableImpl; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import com.jogamp.common.GlueGenVersion; @@ -73,13 +76,14 @@ import com.jogamp.common.util.VersionUtil; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.nativewindow.swt.SWTAccessor; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.opengl.JoglVersion; /** * Native SWT Canvas implementing GLAutoDrawable - * - *

Note: To employ custom GLCapabilities, NewtCanvasSWT shall be used instead.

- * + *

+ * Implementation allows use of custom {@link GLCapabilities}. + *

*/ public class GLCanvas extends Canvas implements GLAutoDrawable { private static final boolean DEBUG = Debug.debug("GLCanvas"); @@ -103,11 +107,15 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final GLCapabilitiesImmutable capsRequested; private final GLCapabilitiesChooser capsChooser; + private volatile Rectangle clientArea; private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access - private GLContextImpl context; + private volatile GLContextImpl context; /* Native window surface */ - private AbstractGraphicsDevice device; + private final boolean useX11GTK; + private volatile long gdkWindow; // either GDK child window .. + private volatile long x11Window; // .. or X11 child window (for GL rendering) + private final AbstractGraphicsScreen screen; /* Construction parameters stored for GLAutoDrawable accessor methods */ private int additionalCtxCreationFlags = 0; @@ -135,7 +143,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void run() { if (sendReshape) { - helper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); + helper.reshape(GLCanvas.this, 0, 0, clientArea.width, clientArea.height); sendReshape = false; } helper.display(GLCanvas.this); @@ -143,7 +151,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { }; /* Action to make specified context current prior to running displayAction */ - private final Runnable makeCurrentAndDisplayOnEDTAction = new Runnable() { + private final Runnable makeCurrentAndDisplayOnGLAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; @@ -159,13 +167,14 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { }; /* Swaps buffers, assuming the GLContext is current */ - private final Runnable swapBuffersOnEDTAction = new Runnable() { + private final Runnable swapBuffersOnGLAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; _lock.lock(); try { - if(null != drawable && !GLCanvas.this.isDisposed() ) { + final boolean drawableOK = null != drawable && drawable.isRealized(); + if( drawableOK && !GLCanvas.this.isDisposed() ) { drawable.swapBuffers(); } } finally { @@ -212,10 +221,14 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { drawable.setRealized(false); drawable = null; } - if (null != device) { - device.close(); - device = null; + if( 0 != x11Window) { + SWTAccessor.destroyX11Window(screen.getDevice(), x11Window); + x11Window = 0; + } else if( 0 != gdkWindow) { + SWTAccessor.destroyGDKWindow(gdkWindow); + gdkWindow = 0; } + screen.getDevice().close(); if (animatorPaused) { animator.resume(); @@ -249,11 +262,6 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } }; - /** - * Storage for the client area rectangle so that it may be accessed from outside of the SWT thread. - */ - private volatile Rectangle clientArea; - /** * Creates an instance using {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser, GLContext)} * on the SWT thread. @@ -293,72 +301,80 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { * @param style * Optional SWT style bit-field. The {@link SWT#NO_BACKGROUND} bit is set before passing this up to the * Canvas constructor, so OpenGL handles the background. - * @param caps + * @param capsReqUser * Optional GLCapabilities. If not provided, the default capabilities for the default GLProfile for the * graphics device determined by the parent Composite are used. Note that the GLCapabilities that are * actually used may differ based on the capabilities of the graphics device. - * @param chooser + * @param capsChooser * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the * requested GLCapabilities, and the available capabilities of the graphics device. * @param shareWith * Optional GLContext to share state (textures, vbos, shaders, etc.) with. */ - public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable caps, - final GLCapabilitiesChooser chooser, final GLContext shareWith) { + public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable capsReqUser, + final GLCapabilitiesChooser capsChooser, final GLContext shareWith) { /* NO_BACKGROUND required to avoid clearing bg in native SWT widget (we do this in the GL display) */ super(parent, style | SWT.NO_BACKGROUND); GLProfile.initSingleton(); // ensure JOGL is completly initialized SWTAccessor.setRealized(this, true); - + clientArea = GLCanvas.this.getClientArea(); /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite). * Note: SWT is owner of the native handle, hence closing operation will be a NOP. */ - device = SWTAccessor.getDevice(this); + final AbstractGraphicsDevice swtDevice = SWTAccessor.getDevice(this); + + useX11GTK = SWTAccessor.useX11GTK(); + if(useX11GTK) { + // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering + final long x11DeviceHandle = X11Util.openDisplay(swtDevice.getConnection()); + if( 0 == x11DeviceHandle ) { + throw new RuntimeException("Error creating display(EDT): "+swtDevice.getConnection()); + } + final AbstractGraphicsDevice x11Device = new X11GraphicsDevice(x11DeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); + screen = SWTAccessor.getScreen(x11Device, -1 /* default */); + } else { + screen = SWTAccessor.getScreen(swtDevice, -1 /* default */); + } /* Select default GLCapabilities if none was provided, otherwise clone provided caps to ensure safety */ - if(null == caps) { - caps = new GLCapabilities(GLProfile.getDefault(device)); + if(null == capsReqUser) { + capsReqUser = new GLCapabilities(GLProfile.getDefault(screen.getDevice())); } - this.capsRequested = caps; - this.capsChooser = chooser; + + this.capsRequested = capsReqUser; + this.capsChooser = capsChooser; this.shareWith = shareWith; // post create .. when ready + gdkWindow = 0; + x11Window = 0; drawable = null; context = null; - /* Register SWT listeners (e.g. PaintListener) to render/resize GL surface. */ - /* TODO: verify that these do not need to be manually de-registered when destroying the SWT component */ - addPaintListener(new PaintListener() { - @Override - public void paintControl(final PaintEvent arg0) { - if ( !helper.isAnimatorAnimatingOnOtherThread() ) { - display(); // checks: null != drawable - } - } - }); - - addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(final ControlEvent arg0) { - updateSizeCheck(); - } - }); - - addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - GLCanvas.this.dispose(); - } - }); + final Listener listener = new Listener () { + @Override + public void handleEvent (Event event) { + switch (event.type) { + case SWT.Paint: + displayIfNoAnimatorNoCheck(); + break; + case SWT.Resize: + updateSizeCheck(); + break; + case SWT.Dispose: + GLCanvas.this.dispose(); + break; + } + } + }; + addListener (SWT.Resize, listener); + addListener (SWT.Paint, listener); + addListener (SWT.Dispose, listener); } + private final UpstreamSurfaceHook swtCanvasUpStreamHook = new UpstreamSurfaceHook() { @Override public final void create(ProxySurface s) { /* nop */ } @@ -390,11 +406,13 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { ) { clientArea = nClientArea; // write back new value - GLDrawableImpl _drawable = drawable; - if( null != _drawable ) { - if(DEBUG) { - System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle())); - } + final GLDrawableImpl _drawable = drawable; + final boolean drawableOK = null != _drawable && _drawable.isRealized(); + if(DEBUG) { + final long dh = drawableOK ? _drawable.getHandle() : 0; + System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - drawableHandle 0x"+Long.toHexString(dh)); + } + if( drawableOK ) { if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { final RecursiveLock _lock = lock; _lock.lock(); @@ -407,66 +425,154 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } finally { _lock.unlock(); } - } - sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock - } + } + } + if(0 != x11Window) { + SWTAccessor.resizeX11Window(screen.getDevice(), clientArea, x11Window); + } else if(0 != gdkWindow) { + SWTAccessor.resizeGDKWindow(clientArea, gdkWindow); + } + sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock } } - @Override - public void display() { - if( null != drawable || validateDrawableAndContext() ) { - runInGLThread(makeCurrentAndDisplayOnEDTAction); - } + private boolean isValidAndVisibleOnEDTActionResult; + private final Runnable isValidAndVisibleOnEDTAction = new Runnable() { + @Override + public void run() { + isValidAndVisibleOnEDTActionResult = !GLCanvas.this.isDisposed() && GLCanvas.this.isVisible(); + } }; + + private final boolean isValidAndVisibleOnEDT() { + synchronized(isValidAndVisibleOnEDTAction) { + runOnEDTIfAvail(true, isValidAndVisibleOnEDTAction); + return isValidAndVisibleOnEDTActionResult; + } } - - /** assumes drawable == null ! */ - protected final boolean validateDrawableAndContext() { - if( isDisposed() || !isVisible() ) { + /** assumes drawable == null || !drawable.isRealized() ! Checks of !isDispose() and isVisible() */ + protected final boolean validateDrawableAndContextWithCheck() { + if( !isValidAndVisibleOnEDT() ) { return false; } + return validateDrawableAndContextPostCheck(); + } + + /** assumes drawable == null || !drawable.isRealized() ! No check of !isDispose() and isVisible() */ + protected final boolean validateDrawableAndContextPostCheck() { final Rectangle nClientArea = clientArea; if(0 >= nClientArea.width || 0 >= nClientArea.height) { return false; } + final boolean res; final RecursiveLock _lock = lock; _lock.lock(); try { - final GLDrawableFactory glFactory = GLDrawableFactory.getFactory(capsRequested.getGLProfile()); - - /* Native handle for the control, used to associate with GLContext */ - final long nativeWindowHandle = SWTAccessor.getWindowHandle(this); - - /* Create a NativeWindow proxy for the SWT canvas */ - ProxySurface proxySurface = null; - try { - proxySurface = glFactory.createProxySurface(device, 0 /* screenIdx */, nativeWindowHandle, - capsRequested, capsChooser, swtCanvasUpStreamHook); - } catch (GLException gle) { - // not ready yet .. - if(DEBUG) { System.err.println(gle.getMessage()); } + if(null == drawable) { + createDrawableAndContext(); } - - if(null != proxySurface) { - /* Associate a GL surface with the proxy */ - drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); + if(null != drawable) { drawable.setRealized(true); - - context = (GLContextImpl) drawable.createContext(shareWith); + res = drawable.isRealized(); + } else { + res = false; } } finally { _lock.unlock(); + } + + if(res) { + sendReshape = true; + if(DEBUG) { + System.err.println("SWT GLCanvas realized! "+this+", "+drawable); + // Thread.dumpStack(); + } } - final boolean res = null != drawable; - if(DEBUG && res) { - System.err.println("SWT GLCanvas realized! "+this+", "+drawable); - Thread.dumpStack(); - } - return res; + return res; + } + + private final void createDrawableAndContext() { + final AbstractGraphicsDevice device = screen.getDevice(); + device.open(); + + final long nativeWindowHandle; + if( useX11GTK ) { + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(device, capsRequested); + final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( + capsRequested, capsRequested, capsChooser, screen, VisualIDHolder.VID_UNDEFINED); + if(DEBUG) { + System.err.println("SWT.GLCanvas.X11 factory: "+factory+", chosen config: "+cfg); + } + if (null == cfg) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + final int visualID = cfg.getVisualID(VIDType.NATIVE); + if( VisualIDHolder.VID_UNDEFINED != visualID ) { + // gdkWindow = SWTAccessor.createCompatibleGDKChildWindow(this, visualID, clientArea.width, clientArea.height); + // nativeWindowHandle = SWTAccessor.gdk_window_get_xwindow(gdkWindow); + x11Window = SWTAccessor.createCompatibleX11ChildWindow(screen, this, visualID, clientArea.width, clientArea.height); + nativeWindowHandle = x11Window; + } else { + throw new GLException("Could not choose valid visualID: 0x"+Integer.toHexString(visualID)+", "+this); + } + } else { + nativeWindowHandle = SWTAccessor.getWindowHandle(this); + } + final GLDrawableFactory glFactory = GLDrawableFactory.getFactory(capsRequested.getGLProfile()); + + // Create a NativeWindow proxy for the SWT canvas + ProxySurface proxySurface = glFactory.createProxySurface(device, screen.getIndex(), nativeWindowHandle, + capsRequested, capsChooser, swtCanvasUpStreamHook); + // Associate a GL surface with the proxy + drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); + context = (GLContextImpl) drawable.createContext(shareWith); + context.setContextCreationFlags(additionalCtxCreationFlags); + } + + @Override + public void update() { + // don't paint background etc .. nop avoids flickering + // super.update(); + } + + /** + @Override + public boolean forceFocus() { + final boolean r = super.forceFocus(); + if(r && 0 != gdkWindow) { + SWTGTKUtil.focusGDKWindow(gdkWindow); + } + return r; + } */ + + @Override + public void dispose() { + runInGLThread(disposeOnEDTGLAction); + super.dispose(); + } + + private final void displayIfNoAnimatorNoCheck() { + if ( !helper.isAnimatorAnimatingOnOtherThread() ) { + final boolean drawableOK = null != drawable && drawable.isRealized(); + if( drawableOK || validateDrawableAndContextPostCheck() ) { + runInGLThread(makeCurrentAndDisplayOnGLAction); + } + } } + // + // GL[Auto]Drawable + // + + @Override + public void display() { + final boolean drawableOK = null != drawable && drawable.isRealized(); + if( drawableOK || validateDrawableAndContextWithCheck() ) { + runInGLThread(makeCurrentAndDisplayOnGLAction); + } + } + @Override public final Object getUpstreamWidget() { return this; @@ -692,18 +798,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void swapBuffers() throws GLException { - runInGLThread(swapBuffersOnEDTAction); - } - - @Override - public void update() { - // don't paint background etc .. nop avoids flickering - } - - @Override - public void dispose() { - runInGLThread(disposeOnEDTGLAction); - super.dispose(); + runInGLThread(swapBuffersOnGLAction); } /** @@ -746,7 +841,32 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } */ action.run(); } + + private void runOnEDTIfAvail(boolean wait, final Runnable action) { + final Display d = isDisposed() ? null : getDisplay(); + if( null == d || d.isDisposed() || d.getThread() == Thread.currentThread() ) { + action.run(); + } else if(wait) { + d.syncExec(action); + } else { + d.asyncExec(action); + } + } + + @Override + public String toString() { + final GLDrawable _drawable = drawable; + final int dw = (null!=_drawable) ? _drawable.getWidth() : -1; + final int dh = (null!=_drawable) ? _drawable.getHeight() : -1; + return "SWT-GLCanvas[Realized "+isRealized()+ + ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+ + ",\n\tFactory "+getFactory()+ + ",\n\thandle 0x"+Long.toHexString(getHandle())+ + ",\n\tDrawable size "+dw+"x"+dh+ + ",\n\tSWT size "+getWidth()+"x"+getHeight()+"]"; + } + public static void main(final String[] args) { System.err.println(VersionUtil.getPlatformInfo()); System.err.println(GlueGenVersion.getInstance()); diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java index e208cfb28..eba26c7d3 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java @@ -34,6 +34,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; import javax.media.nativewindow.AbstractGraphicsScreen; @@ -59,12 +60,22 @@ public class SWTAccessor { private static final Field swt_control_handle; private static final boolean swt_uses_long_handles; + private static Object swt_osx_init = new Object(); + private static Field swt_osx_control_view = null; + private static Field swt_osx_view_id = null; + + private static final String nwt; + private static final boolean isOSX; + private static final boolean isWindows; + private static final boolean isX11; + private static final boolean isX11GTK; + // X11/GTK, Windows/GDI, .. private static final String str_handle = "handle"; // OSX/Cocoa - private static final String str_view = "view"; // OSX - private static final String str_id = "id"; // OSX + private static final String str_osx_view = "view"; // OSX + private static final String str_osx_id = "id"; // OSX // static final String str_NSView = "org.eclipse.swt.internal.cocoa.NSView"; private static final Method swt_control_internal_new_GC; @@ -73,9 +84,10 @@ public class SWTAccessor { private static final String str_internal_dispose_GC = "internal_dispose_GC"; private static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS"; - private static final Class OS_gtk_class; + public static final Class OS_gtk_class; private static final String str_OS_gtk_version = "GTK_VERSION"; - private static final VersionNumber OS_gtk_version; + public static final VersionNumber OS_gtk_version; + private static final Method OS_gtk_widget_realize; private static final Method OS_gtk_widget_unrealize; // optional (removed in SWT 4.3) private static final Method OS_GTK_WIDGET_WINDOW; @@ -85,6 +97,8 @@ public class SWTAccessor { private static final Method OS_gdk_window_get_display; private static final Method OS_gdk_x11_drawable_get_xid; private static final Method OS_gdk_x11_window_get_xid; + private static final Method OS_gdk_window_set_back_pixmap; + private static final String str_gtk_widget_realize = "gtk_widget_realize"; private static final String str_gtk_widget_unrealize = "gtk_widget_unrealize"; private static final String str_GTK_WIDGET_WINDOW = "GTK_WIDGET_WINDOW"; @@ -94,6 +108,7 @@ public class SWTAccessor { private static final String str_gdk_window_get_display = "gdk_window_get_display"; private static final String str_gdk_x11_drawable_get_xid = "gdk_x11_drawable_get_xid"; private static final String str_gdk_x11_window_get_xid = "gdk_x11_window_get_xid"; + private static final String str_gdk_window_set_back_pixmap = "gdk_window_set_back_pixmap"; private static final VersionNumber GTK_VERSION_2_14_0 = new VersionNumber(2, 14, 0); private static final VersionNumber GTK_VERSION_2_24_0 = new VersionNumber(2, 24, 0); @@ -108,23 +123,25 @@ public class SWTAccessor { } static { - Field f = null; - AccessController.doPrivileged(new PrivilegedAction() { public Object run() { NativeWindowFactory.initSingleton(); // last resort .. return null; } } ); - final String nwt = NativeWindowFactory.getNativeWindowType(false); - - if(NativeWindowFactory.TYPE_MACOSX != nwt ) { + nwt = NativeWindowFactory.getNativeWindowType(false); + isOSX = NativeWindowFactory.TYPE_MACOSX == nwt; + isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt; + isX11 = NativeWindowFactory.TYPE_X11 == nwt; + + Field f = null; + if( !isOSX ) { try { f = Control.class.getField(str_handle); } catch (Exception ex) { throw new NativeWindowException(ex); } - } + } swt_control_handle = f; // maybe null ! boolean ulh; @@ -158,31 +175,32 @@ public class SWTAccessor { Class c=null; VersionNumber _gtk_version = new VersionNumber(0, 0, 0); - Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null; - Class handleType = swt_uses_long_handles ? long.class : int.class ; - if( NativeWindowFactory.TYPE_X11 == nwt ) { + Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null, ma=null; + final Class handleType = swt_uses_long_handles ? long.class : int.class ; + if( isX11 ) { // mandatory try { c = ReflectionUtil.getClass(str_OS_gtk_class, false, SWTAccessor.class.getClassLoader()); Field field_OS_gtk_version = c.getField(str_OS_gtk_version); _gtk_version = GTK_VERSION(field_OS_gtk_version.getInt(null)); m1 = c.getDeclaredMethod(str_gtk_widget_realize, handleType); - if( _gtk_version.compareTo(GTK_VERSION_2_14_0) < 0 ) { - m3 = c.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType); - } else { + if (_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) { m4 = c.getDeclaredMethod(str_gtk_widget_get_window, handleType); - } - if( _gtk_version.compareTo(GTK_VERSION_2_24_0) < 0 ) { - m5 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType); } else { + m3 = c.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType); + } + if (_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) { m6 = c.getDeclaredMethod(str_gdk_x11_display_get_xdisplay, handleType); - m7 = c.getDeclaredMethod(str_gdk_window_get_display, handleType); - } - if( _gtk_version.compareTo(GTK_VERSION_3_0_0) < 0 ) { - m8 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType); + m7 = c.getDeclaredMethod(str_gdk_window_get_display, handleType); } else { + m5 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType); + } + if (_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) { m9 = c.getDeclaredMethod(str_gdk_x11_window_get_xid, handleType); + } else { + m8 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType); } + ma = c.getDeclaredMethod(str_gdk_window_set_back_pixmap, handleType, handleType, boolean.class); } catch (Exception ex) { throw new NativeWindowException(ex); } // optional try { @@ -200,25 +218,31 @@ public class SWTAccessor { OS_gdk_window_get_display = m7; OS_gdk_x11_drawable_get_xid = m8; OS_gdk_x11_window_get_xid = m9; + OS_gdk_window_set_back_pixmap = ma; + + isX11GTK = isX11 && null != OS_gtk_class; if(DEBUG) { System.err.println("SWTAccessor.: GTK Version: "+OS_gtk_version); } } - - - static Object getIntOrLong(long arg) { + + private static Number getIntOrLong(long arg) { if(swt_uses_long_handles) { return new Long(arg); } return new Integer((int) arg); } - static void callStaticMethodL2V(Method m, long arg) { + private static void callStaticMethodL2V(Method m, long arg) { ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); } - static long callStaticMethodL2L(Method m, long arg) { + private static void callStaticMethodLLZ2V(Method m, long arg0, long arg1, boolean arg3) { + ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1), Boolean.valueOf(arg3) }); + } + + private static long callStaticMethodL2L(Method m, long arg) { Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); if(o instanceof Number) { return ((Number)o).longValue(); @@ -226,13 +250,73 @@ public class SWTAccessor { throw new InternalError("SWT method "+m.getName()+" didn't return int or long but "+o.getClass()); } } - + + // + // Public properties + // + public static boolean isUsingLongHandles() { return swt_uses_long_handles; } + public static boolean useX11GTK() { return isX11GTK; } public static VersionNumber GTK_VERSION() { return OS_gtk_version; } + // + // Common GTK + // + + public static long gdk_widget_get_window(long handle) { + final long window; + if (OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) { + window = callStaticMethodL2L(OS_gtk_widget_get_window, handle); + } else { + window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); + } + if(0 == window) { + throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle)); + } + return window; + } + + public static long gdk_window_get_xdisplay(long window) { + final long xdisplay; + if (OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) { + final long display = callStaticMethodL2L(OS_gdk_window_get_display, window); + if(0 == display) { + throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display); + } else { + xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window); + } + if(0 == xdisplay) { + throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + return xdisplay; + } + + public static long gdk_window_get_xwindow(long window) { + final long xWindow; + if (OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) { + xWindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window); + } else { + xWindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window); + } + if(0 == xWindow) { + throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + return xWindow; + } + + public static void gdk_window_set_back_pixmap(long window, long pixmap, boolean parent_relative) { + callStaticMethodLLZ2V(OS_gdk_window_set_back_pixmap, window, pixmap, parent_relative); + } + + // + // Common any toolkit + // + /** * @param swtControl the SWT Control to retrieve the native widget-handle from * @return the native widget-handle @@ -240,15 +324,21 @@ public class SWTAccessor { */ public static long getHandle(Control swtControl) throws NativeWindowException { long h = 0; - if(NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false) ) { - try { - Field fView = Control.class.getField(str_view); - Object view = fView.get(swtControl); - Field fId = view.getClass().getField(str_id); - h = fId.getLong(view); - } catch (Exception ex) { - throw new NativeWindowException(ex); - } + if( isOSX ) { + synchronized(swt_osx_init) { + try { + if(null == swt_osx_view_id) { + swt_osx_control_view = Control.class.getField(str_osx_view); + Object view = swt_osx_control_view.get(swtControl); + swt_osx_view_id = view.getClass().getField(str_osx_id); + h = swt_osx_view_id.getLong(view); + } else { + h = swt_osx_view_id.getLong( swt_osx_control_view.get(swtControl) ); + } + } catch (Exception ex) { + throw new NativeWindowException(ex); + } + } } else { try { h = swt_control_handle.getLong(swtControl); @@ -283,49 +373,6 @@ public class SWTAccessor { } } - private static long gdk_x11_display_get_xdisplay(long window) { - final long xdisplay; - if ( OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0 ) { - final long display = callStaticMethodL2L(OS_gdk_window_get_display, window); - if(0 == display) { - throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window)); - } - xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display); - } else { - xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window); - } - if(0 == xdisplay) { - throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window)); - } - return xdisplay; - } - - private static long gdk_widget_get_window(long handle) { - final long window; - if ( OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0 ) { - window = callStaticMethodL2L(OS_gtk_widget_get_window, handle); - } else { - window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); - } - if(0 == window) { - throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle)); - } - return window; - } - - private static long gdk_window_get_xwindow(long window) { - final long xwindow; - if ( OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0 ) { - xwindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window); - } else { - xwindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window); - } - if(0 == xwindow) { - throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window)); - } - return xwindow; - } - /** * @param swtControl the SWT Control to retrieve the native device handle from * @return the AbstractGraphicsDevice w/ the native device handle @@ -333,43 +380,49 @@ public class SWTAccessor { * @throws UnsupportedOperationException if the windowing system is not supported */ public static AbstractGraphicsDevice getDevice(Control swtControl) throws NativeWindowException, UnsupportedOperationException { - long handle = getHandle(swtControl); - if( null != OS_gtk_class ) { - final long xdisplay0 = gdk_x11_display_get_xdisplay( gdk_widget_get_window( handle ) ); - // final String displayName = X11Lib.XDisplayString(xdisplay0); - // final long xdisplay1 = X11Util.openDisplay(displayName); - // return new X11GraphicsDevice(xdisplay1, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); + final long handle = getHandle(swtControl); + if( isX11GTK ) { + final long xdisplay0 = gdk_window_get_xdisplay( gdk_widget_get_window( handle ) ); return new X11GraphicsDevice(xdisplay0, AbstractGraphicsDevice.DEFAULT_UNIT, false /* owner */); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + if( isWindows ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isOSX ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } + /** + * + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return + * @throws UnsupportedOperationException + */ public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) throws UnsupportedOperationException { - if( null != OS_gtk_class ) { - return new X11GraphicsScreen((X11GraphicsDevice)device, screen); + if( isX11 ) { + X11GraphicsDevice x11Device = (X11GraphicsDevice)device; + if(0 > screen) { + screen = x11Device.getDefaultScreen(); + } + return new X11GraphicsScreen(x11Device, screen); + } + if(0 > screen) { + screen = 0; // FIXME: Needs native API utilization } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return new DefaultGraphicsScreen(device, screen); } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } public static int getNativeVisualID(AbstractGraphicsDevice device, long windowHandle) { - if( null != OS_gtk_class ) { + if( isX11 ) { return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return VisualIDHolder.VID_UNDEFINED; } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); @@ -383,12 +436,13 @@ public class SWTAccessor { */ public static long getWindowHandle(Control swtControl) throws NativeWindowException, UnsupportedOperationException { final long handle = getHandle(swtControl); - if( null != OS_gtk_class ) { + if(0 == handle) { + throw new NativeWindowException("Null SWT handle of SWT control "+swtControl); + } + if( isX11GTK ) { return gdk_window_get_xwindow( gdk_widget_get_window( handle ) ); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return handle; } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); @@ -407,7 +461,7 @@ public class SWTAccessor { throw new InternalError("SWT internal_new_GC did not return int or long but "+o[0].getClass()); } } - + public static void disposeGC(final Control swtControl, final long gc, final GCData gcData) { invoke(true, new Runnable() { public void run() { @@ -437,7 +491,7 @@ public class SWTAccessor { * @see Platform#getOSType() */ public static void invoke(boolean wait, Runnable runnable) { - if( Platform.OS_TYPE == Platform.OSType.MACOS ) { + if( isOSX ) { // Use SWT main thread! Only reliable config w/ -XStartOnMainThread !? OSXUtil.RunOnMainThread(wait, runnable); } else { @@ -445,4 +499,85 @@ public class SWTAccessor { } } + // + // Specific X11 GTK ChildWindow - Using plain X11 native parenting (works well) + // + + public static long createCompatibleX11ChildWindow(AbstractGraphicsScreen screen, Control swtControl, int visualID, int width, int height) { + final long handle = getHandle(swtControl); + final long parentWindow = gdk_widget_get_window( handle ); + gdk_window_set_back_pixmap (parentWindow, 0, false); + + final long x11ParentHandle = gdk_window_get_xwindow(parentWindow); + final long x11WindowHandle = X11Lib.CreateWindow(x11ParentHandle, screen.getDevice().getHandle(), screen.getIndex(), visualID, width, height, true, true); + + return x11WindowHandle; + } + + public static void resizeX11Window(AbstractGraphicsDevice device, Rectangle clientArea, long x11Window) { + X11Lib.SetWindowPosSize(device.getHandle(), x11Window, clientArea.x, clientArea.y, clientArea.width, clientArea.height); + } + public static void destroyX11Window(AbstractGraphicsDevice device, long x11Window) { + X11Lib.DestroyWindow(device.getHandle(), x11Window); + } + + // + // Specific X11 SWT/GTK ChildWindow - Using SWT/GTK native parenting (buggy - sporadic resize flickering, sporadic drop of rendering) + // + // FIXME: Need to use reflection for 32bit access as well ! + // + + // public static final int GDK_WA_TYPE_HINT = 1 << 9; + // public static final int GDK_WA_VISUAL = 1 << 6; + + public static long createCompatibleGDKChildWindow(Control swtControl, int visualID, int width, int height) { + return 0; + /** + final long handle = SWTAccessor.getHandle(swtControl); + final long parentWindow = gdk_widget_get_window( handle ); + + final long screen = OS.gdk_screen_get_default (); + final long gdkvisual = OS.gdk_x11_screen_lookup_visual (screen, visualID); + + final GdkWindowAttr attrs = new GdkWindowAttr(); + attrs.width = width > 0 ? width : 1; + attrs.height = height > 0 ? height : 1; + attrs.event_mask = OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK | + OS.GDK_FOCUS_CHANGE_MASK | OS.GDK_POINTER_MOTION_MASK | + OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK | + OS.GDK_ENTER_NOTIFY_MASK | OS.GDK_LEAVE_NOTIFY_MASK | + OS.GDK_EXPOSURE_MASK | OS.GDK_VISIBILITY_NOTIFY_MASK | + OS.GDK_POINTER_MOTION_HINT_MASK; + attrs.window_type = OS.GDK_WINDOW_CHILD; + attrs.visual = gdkvisual; + + final long childWindow = OS.gdk_window_new (parentWindow, attrs, OS.GDK_WA_VISUAL|GDK_WA_TYPE_HINT); + OS.gdk_window_set_user_data (childWindow, handle); + OS.gdk_window_set_back_pixmap (parentWindow, 0, false); + + OS.gdk_window_show (childWindow); + OS.gdk_flush(); + return childWindow; */ + } + + public static void showGDKWindow(long gdkWindow) { + /* OS.gdk_window_show (gdkWindow); + OS.gdk_flush(); */ + } + public static void focusGDKWindow(long gdkWindow) { + /* + OS.gdk_window_show (gdkWindow); + OS.gdk_window_focus(gdkWindow, 0); + OS.gdk_flush(); */ + } + public static void resizeGDKWindow(Rectangle clientArea, long gdkWindow) { + /** + OS.gdk_window_move (gdkWindow, clientArea.x, clientArea.y); + OS.gdk_window_resize (gdkWindow, clientArea.width, clientArea.height); + OS.gdk_flush(); */ + } + + public static void destroyGDKWindow(long gdkWindow) { + // OS.gdk_window_destroy (gdkWindow); + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java index 67a33e55c..827862002 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java @@ -37,7 +37,7 @@ public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); } if( 0 == s.getSurfaceHandle() ) { - final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64); + final long windowHandle = X11Lib.CreateWindow(0, device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64, false, false); if(0 == windowHandle) { throw new NativeWindowException("Creating dummy window failed w/ "+cfg); } @@ -59,7 +59,7 @@ public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize } device.lock(); try { - X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle()); + X11Lib.DestroyWindow(device.getHandle(), s.getSurfaceHandle()); s.setSurfaceHandle(0); s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } finally { diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index c73952693..a8d45f288 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -31,6 +31,8 @@ #include "jogamp_nativewindow_x11_X11Lib.h" #include "jogamp_nativewindow_x11_X11Util.h" +#include + // #define VERBOSE_ON 1 #ifdef VERBOSE_ON @@ -85,6 +87,8 @@ Bool XF86VidModeSetGammaRamp( #define RTLD_DEFAULT NULL #endif +#define X11_MOUSE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask) + static const char * const ClazzNameBuffers = "com/jogamp/common/nio/Buffers"; static const char * const ClazzNameBuffersStaticCstrName = "copyByteBuffer"; static const char * const ClazzNameBuffersStaticCstrSignature = "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"; @@ -436,17 +440,62 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused return _res; } +static void NativewindowX11_setNormalWindowEWMH (Display *dpy, Window w) { + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[1]={0}; + types[0] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1); + XSync(dpy, False); +} + +#define DECOR_USE_MWM 1 // works for known WMs +// #define DECOR_USE_EWMH 1 // haven't seen this to work (NORMAL->POPUP, never gets undecorated) + +/* see */ +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 + +static void NativewindowX11_setDecorations (Display *dpy, Window w, Bool decorated) { + +#ifdef DECOR_USE_MWM + unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status + Atom _MOTIF_WM_HINTS = XInternAtom( dpy, "_MOTIF_WM_HINTS", False ); +#endif + +#ifdef DECOR_USE_EWMH + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[3]={0}; + int ntypes=0; + if(True==decorated) { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + } else { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False ); + } +#endif + +#ifdef DECOR_USE_MWM + XChangeProperty( dpy, w, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS); +#endif + +#ifdef DECOR_USE_EWMH + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); +#endif + + XSync(dpy, False); +} + /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: CreateDummyWindow - * Signature: (JIIII)J + * Method: CreateWindow + * Signature: (JJIIIIZZ)J */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow - (JNIEnv *env, jclass unused, jlong display, jint screen_index, jint visualID, jint width, jint height) +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow + (JNIEnv *env, jclass unused, jlong parent, jlong display, jint screen_index, jint visualID, jint width, jint height, jboolean input, jboolean visible) { Display * dpy = (Display *)(intptr_t)display; int scrn_idx = (int)screen_index; - Window windowParent = 0; + Window root = RootWindow(dpy, scrn_idx); + Window windowParent = (Window) parent; Window window = 0; XVisualInfo visualTemplate; @@ -473,6 +522,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); + if(0==windowParent) { + windowParent = root; + } // try given VisualID on screen memset(&visualTemplate, 0, sizeof(XVisualInfo)); @@ -500,9 +552,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow pVisualQuery=NULL; } - if(0==windowParent) { - windowParent = XRootWindowOfScreen(scrn); - } attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap | CWBorderPixel | CWColormap | CWOverrideRedirect ) ; @@ -514,15 +563,22 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow xswa.backing_store=NotUseful; /* NotUseful, WhenMapped, Always */ xswa.backing_planes=0; /* planes to be preserved if possible */ xswa.backing_pixel=0; /* value to use in restoring planes */ + if( input ) { + xswa.event_mask = X11_MOUSE_EVENT_MASK; + xswa.event_mask |= KeyPressMask | KeyReleaseMask ; + } + if( visible ) { + xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ; + } xswa.colormap = XCreateColormap(dpy, - XRootWindow(dpy, scrn_idx), + windowParent, visual, AllocNone); window = XCreateWindow(dpy, windowParent, - 0, 0, + 0, 0, // only a hint, WM most likely will override width, height, 0, // border width depth, @@ -530,9 +586,25 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow visual, attrMask, &xswa); + if(0==window) { + NativewindowCommon_throwNewRuntimeException(env, "could not create Window, bail out!"); + return 0; + } + + NativewindowX11_setNormalWindowEWMH(dpy, window); + NativewindowX11_setDecorations(dpy, window, False); + + if( visible ) { + XEvent event; + + XMapWindow(dpy, window); + } + XSync(dpy, False); - XSelectInput(dpy, window, 0); // no events + if( !input ) { + XSelectInput(dpy, window, 0); // no events + } // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); @@ -544,10 +616,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: DestroyDummyWindow + * Method: DestroyWindow * Signature: (JJ)V */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow (JNIEnv *env, jclass unused, jlong display, jlong window) { Display * dpy = (Display *)(intptr_t)display; @@ -559,12 +631,37 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow } NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); + XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); } +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize + (JNIEnv *env, jclass unused, jlong display, jlong window, jint x, jint y, jint width, jint height) { + Display * dpy = (Display *)(intptr_t)display; + Window w = (Window) window; + XWindowChanges xwc; + int flags = 0; + + memset(&xwc, 0, sizeof(XWindowChanges)); + + if(0<=x && 0<=y) { + flags |= CWX | CWY; + xwc.x=x; + xwc.y=y; + } + + if(0 + * Implementation allows use of custom {@link GLCapabilities}. + *

*/ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { private static final boolean DEBUG = Debug.debug("Window"); @@ -126,54 +126,44 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { clientArea = getClientArea(); final AbstractGraphicsDevice device = SWTAccessor.getDevice(this); - screen = SWTAccessor.getScreen(device, 0); + screen = SWTAccessor.getScreen(device, -1 /* default */); nativeWindow = null; if(null != child) { setNEWTChild(child); } - - /* Register SWT listeners (e.g. PaintListener) to render/resize GL surface. */ - /* TODO: verify that these do not need to be manually de-registered when destroying the SWT component */ - addPaintListener(new PaintListener() { + + final Listener listener = new Listener () { @Override - public void paintControl(final PaintEvent arg0) { - if( null != nativeWindow || validateNative() ) { - if( newtChildReady ) { - if( postSetSize ) { - newtChild.setSize(clientArea.width, clientArea.height); - postSetSize = false; + public void handleEvent (Event event) { + switch (event.type) { + case SWT.Paint: + if( null != nativeWindow || validateNative() ) { + if( newtChildReady ) { + if( postSetSize ) { + newtChild.setSize(clientArea.width, clientArea.height); + postSetSize = false; + } + newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height); } - newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height); } + break; + case SWT.Resize: + updateSizeCheck(); + break; + case SWT.Dispose: + NewtCanvasSWT.this.dispose(); + break; } } - }); - - addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - @Override - public void controlResized(final ControlEvent arg0) { - updateSizeCheck(); - } - }); - - addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - NewtCanvasSWT.this.dispose(); - } - }); - + }; + addListener (SWT.Resize, listener); + addListener (SWT.Paint, listener); + addListener (SWT.Dispose, listener); } /** assumes nativeWindow == null ! */ protected final boolean validateNative() { - if( isDisposed() || !isVisible() ) { - return false; - } updateSizeCheck(); final Rectangle nClientArea = clientArea; if(0 >= nClientArea.width || 0 >= nClientArea.height) { @@ -216,6 +206,10 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { ( nClientArea.width != oClientArea.width || nClientArea.height != oClientArea.height ) ) { clientArea = nClientArea; // write back new value + if(DEBUG) { + final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; + System.err.println("NewtCanvasSWT.sizeChanged: ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(nsh)); + } if( newtChildReady ) { newtChild.setSize(clientArea.width, clientArea.height); } else { @@ -223,7 +217,7 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { } } } - + @Override public void update() { // don't paint background etc .. nop avoids flickering @@ -261,11 +255,11 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { public NativeWindow getNativeWindow() { return nativeWindow; } public WindowClosingMode getDefaultCloseOperation() { - return newtChildCloseOp; // FIXME + return newtChildCloseOp; // TODO: implement ?! } public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) { - return newtChildCloseOp = op; // FIXME + return newtChildCloseOp = op; // TODO: implement ?! } diff --git a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java deleted file mode 100644 index 1c20fe524..000000000 --- a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java +++ /dev/null @@ -1,313 +0,0 @@ -/** - * Copyright 2012 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 com.jogamp.newt.swt; - -import javax.media.nativewindow.NativeWindowException; - -import jogamp.newt.Debug; - -import com.jogamp.common.util.RunnableTask; -import com.jogamp.newt.util.EDTUtil; - -/** - * Simple {@link EDTUtil} implementation utilizing the SWT UI thread - * of the given {@link Display}. - */ -public class SWTEDTUtil implements EDTUtil { - public static final boolean DEBUG = Debug.debug("EDT"); - - private final Object edtLock = new Object(); // locking the EDT start/stop state - private final ThreadGroup threadGroup; - private final String name; - private final Runnable dispatchMessages; - private final org.eclipse.swt.widgets.Display swtDisplay; - private NewtEventDispatchThread nedt = null; - private int start_iter=0; - private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; - - public SWTEDTUtil(final com.jogamp.newt.Display newtDisplay, org.eclipse.swt.widgets.Display swtDisplay) { - this.threadGroup = Thread.currentThread().getThreadGroup(); - this.name=Thread.currentThread().getName()+"-SWTDisplay-"+newtDisplay.getFQName()+"-EDT-"; - this.dispatchMessages = new Runnable() { - public void run() { - ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages(); - } }; - this.swtDisplay = swtDisplay; - this.nedt = new NewtEventDispatchThread(threadGroup, name); - this.nedt.setDaemon(true); // don't stop JVM from shutdown .. - } - - public final org.eclipse.swt.widgets.Display getDisplay() { - return swtDisplay; - } - - @Override - public long getPollPeriod() { - return pollPeriod; - } - - @Override - public void setPollPeriod(long ms) { - pollPeriod = ms; - } - - @Override - public void reset() { - synchronized(edtLock) { - waitUntilStopped(); - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt); - } - this.nedt = new NewtEventDispatchThread(threadGroup, name); - this.nedt.setDaemon(true); // don't stop JVM from shutdown .. - } - } - - private final void startImpl() { - if(nedt.isAlive()) { - throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); - } - start_iter++; - nedt.setName(name+start_iter); - nedt.shouldStop = false; - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT START - edt: "+nedt); - // Thread.dumpStack(); - } - nedt.start(); - } - - @Override - public boolean isCurrentThreadEDT() { - return swtDisplay.getThread() == Thread.currentThread(); - } - - @Override - public final boolean isCurrentThreadNEDT() { - return nedt == Thread.currentThread(); - } - - @Override - public final boolean isCurrentThreadEDTorNEDT() { - final Thread ct = Thread.currentThread(); - return ct == swtDisplay.getThread() || ct == nedt ; - } - - @Override - public boolean isRunning() { - return nedt.isRunning() ; // SWT is always running - } - - @Override - public final void invokeStop(Runnable task) { - invokeImpl(true, task, true); - } - - @Override - public final void invoke(boolean wait, Runnable task) { - invokeImpl(wait, task, false); - } - - private void invokeImpl(boolean wait, Runnable task, boolean stop) { - Throwable throwable = null; - RunnableTask rTask = null; - Object rTaskLock = new Object(); - synchronized(rTaskLock) { // lock the optional task execution - synchronized(edtLock) { // lock the EDT status - if( nedt.shouldStop ) { - // drop task .. - if(DEBUG) { - System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt); - Thread.dumpStack(); - } - return; - } - // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); - // Thread.dumpStack(); - if(stop) { - synchronized(nedt.sync) { - nedt.shouldStop = true; - nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) - } - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); - // Thread.dumpStack(); - } - } else if( !nedt.isRunning() ) { - // start if should not stop && not started yet - startImpl(); - } - if( null == task ) { - wait = false; - } else if( isCurrentThreadEDT() ) { - task.run(); - wait = false; // running in same thread (EDT) -> no wait - } else if( swtDisplay.isDisposed() ) { - wait = false; // drop task, SWT disposed - } else { - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - true /* always catch and report Exceptions, don't disturb EDT */); - swtDisplay.asyncExec(rTask); - } - } - if( wait ) { - try { - rTaskLock.wait(); // free lock, allow execution of rTask - } catch (InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); - } - if(null!=throwable) { - if(throwable instanceof NativeWindowException) { - throw (NativeWindowException)throwable; - } - throw new RuntimeException(throwable); - } - } - } - } - - @Override - final public void waitUntilIdle() { - final NewtEventDispatchThread _nedt; - synchronized(edtLock) { - _nedt = nedt; - } - final Thread ct = Thread.currentThread(); - if(!_nedt.isRunning() || _nedt == ct || swtDisplay.getThread() == ct) { - return; - } - try { - swtDisplay.syncExec(new Runnable() { - public void run() { } - }); - } catch (Exception e) { } - } - - @Override - final public void waitUntilStopped() { - synchronized(edtLock) { - final Thread ct = Thread.currentThread(); - if(nedt.isRunning() && nedt != ct && swtDisplay.getThread() != ct) { - while(nedt.isRunning()) { - try { - edtLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - } - - class NewtEventDispatchThread extends Thread { - volatile boolean shouldStop = false; - volatile boolean isRunning = false; - Object sync = new Object(); - - public NewtEventDispatchThread(ThreadGroup tg, String name) { - super(tg, name); - } - - final public boolean isRunning() { - return isRunning; - } - - @Override - final public void start() throws IllegalThreadStateException { - isRunning = true; - super.start(); - } - - /** - * Utilizing locking only on tasks and its execution, - * not for event dispatching. - */ - @Override - final public void run() { - if(DEBUG) { - System.err.println(getName()+": SWT-EDT run() START "+ getName()); - } - RuntimeException error = null; - try { - do { - // event dispatch - if(!shouldStop) { - // EDT invoke thread is SWT-EDT, - // hence dispatching is required to run on SWT-EDT as well. - // Otherwise a deadlock may happen due to dispatched event's - // triggering a locking action. - if ( !swtDisplay.isDisposed() ) { - swtDisplay.syncExec(dispatchMessages); - } else { - dispatchMessages.run(); - } - } - // wait - synchronized(sync) { - if(!shouldStop) { - try { - sync.wait(pollPeriod); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } while(!shouldStop) ; - } catch (Throwable t) { - // handle errors .. - shouldStop = true; - if(t instanceof RuntimeException) { - error = (RuntimeException) t; - } else { - error = new RuntimeException("Within SWT-EDT", t); - } - } finally { - if(DEBUG) { - System.err.println(getName()+": SWT-EDT run() END "+ getName()+", "+error); - } - synchronized(edtLock) { - isRunning = !shouldStop; - if(!isRunning) { - edtLock.notifyAll(); - } - } - if(DEBUG) { - System.err.println(getName()+": SWT-EDT run() EXIT "+ getName()+", exception: "+error); - } - if(null!=error) { - throw error; - } - } // finally - } // run() - } // EventDispatchThread - -} diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java new file mode 100644 index 000000000..7297e5858 --- /dev/null +++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java @@ -0,0 +1,313 @@ +/** + * Copyright 2012 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.newt.swt; + +import javax.media.nativewindow.NativeWindowException; + +import jogamp.newt.Debug; + +import com.jogamp.common.util.RunnableTask; +import com.jogamp.newt.util.EDTUtil; + +/** + * Simple {@link EDTUtil} implementation utilizing the SWT UI thread + * of the given {@link Display}. + */ +public class SWTEDTUtil implements EDTUtil { + public static final boolean DEBUG = Debug.debug("EDT"); + + private final Object edtLock = new Object(); // locking the EDT start/stop state + private final ThreadGroup threadGroup; + private final String name; + private final Runnable dispatchMessages; + private final org.eclipse.swt.widgets.Display swtDisplay; + private NewtEventDispatchThread nedt = null; + private int start_iter=0; + private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; + + public SWTEDTUtil(final com.jogamp.newt.Display newtDisplay, org.eclipse.swt.widgets.Display swtDisplay) { + this.threadGroup = Thread.currentThread().getThreadGroup(); + this.name=Thread.currentThread().getName()+"-SWTDisplay-"+newtDisplay.getFQName()+"-EDT-"; + this.dispatchMessages = new Runnable() { + public void run() { + ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages(); + } }; + this.swtDisplay = swtDisplay; + this.nedt = new NewtEventDispatchThread(threadGroup, name); + this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + + public final org.eclipse.swt.widgets.Display getDisplay() { + return swtDisplay; + } + + @Override + public long getPollPeriod() { + return pollPeriod; + } + + @Override + public void setPollPeriod(long ms) { + pollPeriod = ms; + } + + @Override + public void reset() { + synchronized(edtLock) { + waitUntilStopped(); + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt); + } + this.nedt = new NewtEventDispatchThread(threadGroup, name); + this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + } + + private final void startImpl() { + if(nedt.isAlive()) { + throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); + } + start_iter++; + nedt.setName(name+start_iter); + nedt.shouldStop = false; + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT START - edt: "+nedt); + // Thread.dumpStack(); + } + nedt.start(); + } + + @Override + public boolean isCurrentThreadEDT() { + return swtDisplay.getThread() == Thread.currentThread(); + } + + @Override + public final boolean isCurrentThreadNEDT() { + return nedt == Thread.currentThread(); + } + + @Override + public final boolean isCurrentThreadEDTorNEDT() { + final Thread ct = Thread.currentThread(); + return ct == swtDisplay.getThread() || ct == nedt ; + } + + @Override + public boolean isRunning() { + return nedt.isRunning() ; // SWT is always running + } + + @Override + public final void invokeStop(Runnable task) { + invokeImpl(true, task, true); + } + + @Override + public final void invoke(boolean wait, Runnable task) { + invokeImpl(wait, task, false); + } + + private void invokeImpl(boolean wait, Runnable task, boolean stop) { + Throwable throwable = null; + RunnableTask rTask = null; + Object rTaskLock = new Object(); + synchronized(rTaskLock) { // lock the optional task execution + synchronized(edtLock) { // lock the EDT status + if( nedt.shouldStop ) { + // drop task .. + if(DEBUG) { + System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt); + Thread.dumpStack(); + } + return; + } + // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); + // Thread.dumpStack(); + if(stop) { + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); + // Thread.dumpStack(); + } + } else if( !nedt.isRunning() ) { + // start if should not stop && not started yet + startImpl(); + } + if( null == task ) { + wait = false; + } else if( isCurrentThreadEDT() ) { + task.run(); + wait = false; // running in same thread (EDT) -> no wait + } else if( swtDisplay.isDisposed() ) { + wait = false; // drop task, SWT disposed + } else { + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */); + swtDisplay.asyncExec(rTask); + } + } + if( wait ) { + try { + rTaskLock.wait(); // free lock, allow execution of rTask + } catch (InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rTask.getThrowable(); + } + if(null!=throwable) { + if(throwable instanceof NativeWindowException) { + throw (NativeWindowException)throwable; + } + throw new RuntimeException(throwable); + } + } + } + } + + @Override + final public void waitUntilIdle() { + final NewtEventDispatchThread _nedt; + synchronized(edtLock) { + _nedt = nedt; + } + final Thread ct = Thread.currentThread(); + if(!_nedt.isRunning() || _nedt == ct || swtDisplay.getThread() == ct) { + return; + } + try { + swtDisplay.syncExec(new Runnable() { + public void run() { } + }); + } catch (Exception e) { } + } + + @Override + final public void waitUntilStopped() { + synchronized(edtLock) { + final Thread ct = Thread.currentThread(); + if(nedt.isRunning() && nedt != ct && swtDisplay.getThread() != ct) { + while(nedt.isRunning()) { + try { + edtLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + + class NewtEventDispatchThread extends Thread { + volatile boolean shouldStop = false; + volatile boolean isRunning = false; + Object sync = new Object(); + + public NewtEventDispatchThread(ThreadGroup tg, String name) { + super(tg, name); + } + + final public boolean isRunning() { + return isRunning; + } + + @Override + final public void start() throws IllegalThreadStateException { + isRunning = true; + super.start(); + } + + /** + * Utilizing locking only on tasks and its execution, + * not for event dispatching. + */ + @Override + final public void run() { + if(DEBUG) { + System.err.println(getName()+": SWT-EDT run() START "+ getName()); + } + RuntimeException error = null; + try { + do { + // event dispatch + if(!shouldStop) { + // EDT invoke thread is SWT-EDT, + // hence dispatching is required to run on SWT-EDT as well. + // Otherwise a deadlock may happen due to dispatched event's + // triggering a locking action. + if ( !swtDisplay.isDisposed() ) { + swtDisplay.syncExec(dispatchMessages); + } else { + dispatchMessages.run(); + } + } + // wait + synchronized(sync) { + if(!shouldStop) { + try { + sync.wait(pollPeriod); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } while(!shouldStop) ; + } catch (Throwable t) { + // handle errors .. + shouldStop = true; + if(t instanceof RuntimeException) { + error = (RuntimeException) t; + } else { + error = new RuntimeException("Within SWT-EDT", t); + } + } finally { + if(DEBUG) { + System.err.println(getName()+": SWT-EDT run() END "+ getName()+", "+error); + } + synchronized(edtLock) { + isRunning = !shouldStop; + if(!isRunning) { + edtLock.notifyAll(); + } + } + if(DEBUG) { + System.err.println(getName()+": SWT-EDT run() EXIT "+ getName()+", exception: "+error); + } + if(null!=error) { + throw error; + } + } // finally + } // run() + } // EventDispatchThread + +} diff --git a/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java new file mode 100644 index 000000000..e238f5d9e --- /dev/null +++ b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java @@ -0,0 +1,249 @@ +/** + * Copyright 2012 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.newt.swt.event; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.newt.event.InputEvent; + +/** + * SWT event translator to NEWT, inclusive dispatch listener. + *

+ * Disclaimer: This code is merely tested and subject to change. + *

+ */ +public class SWTNewtEventFactory { + + protected static final IntIntHashMap eventTypeSWT2NEWT; + + static { + IntIntHashMap map = new IntIntHashMap(); + map.setKeyNotFoundValue(0xFFFFFFFF); + + // map.put(SWT.MouseXXX, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED); + map.put(SWT.MouseDown, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED); + map.put(SWT.MouseUp, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED); + map.put(SWT.MouseMove, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED); + map.put(SWT.MouseEnter, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_ENTERED); + map.put(SWT.MouseExit, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_EXITED); + // map.put(SWT.MouseXXX, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED); + map.put(SWT.MouseVerticalWheel, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED); + + map.put(SWT.KeyDown, com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED); + map.put(SWT.KeyUp, com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED); + // map.put(SWT.KeyXXX, com.jogamp.newt.event.KeyEvent.EVENT_KEY_TYPED); + + eventTypeSWT2NEWT = map; + } + + public static final int swtModifiers2Newt(int awtMods, boolean mouseHint) { + int newtMods = 0; + if ((awtMods & SWT.SHIFT) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK; + if ((awtMods & SWT.CTRL) != 0) newtMods |= com.jogamp.newt.event.InputEvent.CTRL_MASK; + if ((awtMods & SWT.ALT) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK; + return newtMods; + } + + public static final com.jogamp.newt.event.InputEvent createInputEvent(org.eclipse.swt.widgets.Event event, Object source) { + com.jogamp.newt.event.InputEvent res = createMouseEvent(event, source); + if(null == res) { + res = createKeyEvent(event, source); + } + return res; + } + + public static final com.jogamp.newt.event.MouseEvent createMouseEvent(org.eclipse.swt.widgets.Event event, Object source) { + switch(event.type) { + case SWT.MouseDown: + case SWT.MouseUp: + case SWT.MouseMove: + case SWT.MouseEnter: + case SWT.MouseExit: + case SWT.MouseVerticalWheel: + break; + default: + return null; + } + int type = eventTypeSWT2NEWT.get(event.type); + if(0xFFFFFFFF != type) { + int rotation = 0; + if (SWT.MouseVerticalWheel == event.type) { + // SWT/NEWT rotation is reversed - AWT +1 is down, NEWT +1 is up. + // rotation = -1 * (int) event.rotation; + rotation = (int) event.rotation; + } + + int mods = swtModifiers2Newt(event.stateMask, true); + + if( source instanceof com.jogamp.newt.Window) { + final com.jogamp.newt.Window newtSource = (com.jogamp.newt.Window)source; + if(newtSource.isPointerConfined()) { + mods |= InputEvent.CONFINED_MASK; + } + if(!newtSource.isPointerVisible()) { + mods |= InputEvent.INVISIBLE_MASK; + } + } + + return new com.jogamp.newt.event.MouseEvent( + type, (null==source)?(Object)event.data:source, (0xFFFFFFFFL & (long)event.time), + mods, event.x, event.y, event.count, event.button, rotation); + } + return null; // no mapping .. + } + + public static final com.jogamp.newt.event.KeyEvent createKeyEvent(org.eclipse.swt.widgets.Event event, Object source) { + switch(event.type) { + case SWT.KeyDown: + case SWT.KeyUp: + break; + default: + return null; + } + int type = eventTypeSWT2NEWT.get(event.type); + if(0xFFFFFFFF != type) { + return new com.jogamp.newt.event.KeyEvent( + type, (null==source)?(Object)event.data:source, (0xFFFFFFFFL & (long)event.time), + swtModifiers2Newt(event.stateMask, false), + event.keyCode, event.character); + } + return null; // no mapping .. + } + + // + // + // + + int dragButtonDown = 0; + + public SWTNewtEventFactory() { + resetButtonsDown(); + } + + final void resetButtonsDown() { + dragButtonDown = 0; + } + + public final boolean dispatchMouseEvent(org.eclipse.swt.widgets.Event event, Object source, com.jogamp.newt.event.MouseListener l) { + com.jogamp.newt.event.MouseEvent res = createMouseEvent(event, source); + if(null != res) { + if(null != l) { + switch(event.type) { + case SWT.MouseDown: + dragButtonDown = event.button; + l.mousePressed(res); break; + case SWT.MouseUp: + dragButtonDown = 0; + l.mouseReleased(res); + { + final com.jogamp.newt.event.MouseEvent res2 = new com.jogamp.newt.event.MouseEvent( + com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED, + res.getSource(), + res.getWhen(), res.getModifiers(), + res.getX(), res.getY(), res.getClickCount(), + res.getButton(), res.getWheelRotation() ); + l.mouseClicked(res2); + } + break; + case SWT.MouseMove: + if( 0 < dragButtonDown ) { + final com.jogamp.newt.event.MouseEvent res2 = new com.jogamp.newt.event.MouseEvent( + com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED, + res.getSource(), + res.getWhen(), res.getModifiers(), + res.getX(), res.getY(), res.getClickCount(), + dragButtonDown, res.getWheelRotation() ); + l.mouseDragged( res2 ); + } else { + l.mouseMoved(res); + } + break; + case SWT.MouseEnter: + l.mouseEntered(res); + break; + case SWT.MouseExit: + resetButtonsDown(); + l.mouseExited(res); + break; + case SWT.MouseVerticalWheel: + l.mouseWheelMoved(res); + break; + } + } + return true; + } + return false; + } + + public final boolean dispatchKeyEvent(org.eclipse.swt.widgets.Event event, Object source, com.jogamp.newt.event.KeyListener l) { + com.jogamp.newt.event.KeyEvent res = createKeyEvent(event, source); + if(null != res) { + if(null != l) { + switch(event.type) { + case SWT.KeyDown: + l.keyPressed(res); + break; + case SWT.KeyUp: + l.keyReleased(res); + l.keyTyped(res); + break; + } + } + return true; + } + return false; + } + + public final void attachDispatchListener(final org.eclipse.swt.widgets.Control ctrl, final Object source, + final com.jogamp.newt.event.MouseListener ml, + final com.jogamp.newt.event.KeyListener kl) { + final Listener listener = new Listener () { + @Override + public void handleEvent (Event event) { + if( dispatchMouseEvent( event, source, ml ) ) { + return; + } + if( dispatchKeyEvent( event, source, kl ) ) { + return; + } + } }; + ctrl.addListener(SWT.MouseDown, listener); + ctrl.addListener(SWT.MouseUp, listener); + ctrl.addListener(SWT.MouseMove, listener); + ctrl.addListener(SWT.MouseEnter, listener); + ctrl.addListener(SWT.MouseExit, listener); + ctrl.addListener(SWT.MouseVerticalWheel, listener); + ctrl.addListener(SWT.KeyDown, listener); + ctrl.addListener(SWT.KeyUp, listener); + } +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index e9fe9b401..a3023538f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -60,8 +60,8 @@ public class GearsES2 implements GLEventListener { private int swapInterval = 0; private boolean pmvUseBackingArray = true; // the default for PMVMatrix now, since it's faster // private MouseListener gearsMouse = new TraceMouseAdapter(new GearsMouseAdapter()); - private MouseListener gearsMouse = new GearsMouseAdapter(); - private KeyListener gearsKeys = new GearsKeyAdapter(); + public MouseListener gearsMouse = new GearsMouseAdapter(); + public KeyListener gearsKeys = new GearsKeyAdapter(); private int prevMouseX, prevMouseY; private boolean doRotate = true; @@ -352,6 +352,10 @@ public class GearsES2 implements GLEventListener { window = (Window) source; width=window.getWidth(); height=window.getHeight(); + } else if (source instanceof GLAutoDrawable) { + GLAutoDrawable glad = (GLAutoDrawable) source; + width = glad.getWidth(); + height = glad.getHeight(); } else if (GLProfile.isAWTAvailable() && source instanceof java.awt.Component) { java.awt.Component comp = (java.awt.Component) source; width=comp.getWidth(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java index a0874e609..1f3bf3156 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java @@ -366,8 +366,9 @@ public class TestNewtCanvasSWTBug628ResizeDeadlock extends UITestCase { try { while( !shallStop && !dsc.display.isDisposed() ) { - if( !dsc.display.readAndDispatch() ) { - dsc.display.sleep(); + if( !dsc.display.readAndDispatch() && !shallStop ) { + // blocks on linux .. dsc.display.sleep(); + Thread.sleep(10); } } } catch (Exception e0) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java index 0a47b96eb..97b3ab243 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java @@ -45,12 +45,13 @@ import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities ; import javax.media.opengl.GLProfile; +import jogamp.newt.swt.SWTEDTUtil; +import jogamp.newt.swt.event.SWTNewtEventFactory; import junit.framework.Assert; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.newt.opengl.GLWindow ; import com.jogamp.newt.swt.NewtCanvasSWT ; -import com.jogamp.newt.swt.SWTEDTUtil; import com.jogamp.opengl.swt.GLCanvas; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; @@ -121,15 +122,15 @@ public class TestSWTBug643AsyncExec extends UITestCase { final Runnable swtAsyncAction = new Runnable() { public void run() { - ++swtN ; - System.err.println("[SWT A-i shallStop "+shallStop+"]: Counter[loc "+swtN+", glob: "+incrSWTCount()+"]"); + ++swtN ; incrSWTCount(); + System.err.println("[SWT A-i shallStop "+shallStop+"]: Counter[loc "+swtN+", glob: "+getSWTCount()+"]"); } }; final Runnable newtAsyncAction = new Runnable() { public void run() { - ++newtN ; - System.err.println("[NEWT A-i shallStop "+shallStop+"]: Counter[loc "+newtN+", glob: "+incrNEWTCount()+"]"); + ++newtN ; incrNEWTCount(); + System.err.println("[NEWT A-i shallStop "+shallStop+"]: Counter[loc "+newtN+", glob: "+getNEWTCount()+"]"); } }; public void run() @@ -219,9 +220,13 @@ public class TestSWTBug643AsyncExec extends UITestCase { final GLAutoDrawable glad; if( useJOGLGLCanvas ) { - glad = GLCanvas.create(dsc.composite, 0, caps, null, null); - glad.addGLEventListener( new GearsES2() ) ; - newtDisplay = null; + final GearsES2 demo = new GearsES2(); + final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null, null); + final SWTNewtEventFactory swtNewtEventFactory = new SWTNewtEventFactory(); + swtNewtEventFactory.attachDispatchListener(glc, glc, demo.gearsMouse, demo.gearsKeys); + glc.addGLEventListener( demo ) ; + glad = glc; + newtDisplay = null; } else if( useNewtCanvasSWT ) { final GLWindow glWindow = GLWindow.create( caps ) ; glWindow.addGLEventListener( new GearsES2() ) ; @@ -287,8 +292,9 @@ public class TestSWTBug643AsyncExec extends UITestCase { try { final Display d = dsc.display; while( !shallStop && !d.isDisposed() ) { - if( !d.readAndDispatch() ) { - dsc.display.sleep(); + if( !d.readAndDispatch() && !shallStop ) { + // blocks on linux .. dsc.display.sleep(); + Thread.sleep(10); } } } catch (Exception e0) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java index a5d2c8012..1822d2eaf 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java @@ -50,6 +50,7 @@ import org.junit.Test; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.opengl.swt.GLCanvas; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.jogl.demos.es2.MultisampleDemoES2; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.GLReadBufferUtil; @@ -58,10 +59,9 @@ import com.jogamp.opengl.util.texture.TextureIO; /** * Tests that a basic SWT app can open without crashing under different GL profiles. *

- * Uses JOGL's new SWT GLCanvas. - *

- *

- * Note: To employ custom GLCapabilities, NewtCanvasSWT shall be used. + * Uses JOGL's new SWT GLCanvas, + * which allows utilizing custom GLCapability settings, + * independent from the already instantiated SWT visual. *

*

* Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ @@ -188,6 +188,14 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2() ); } + @Test + public void test_MultisampleAndAlpha() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(GLProfile.getGL2ES2()); + caps.setSampleBuffers(true); + caps.setNumSamples(2); + runTestAGL( caps, new MultisampleDemoES2(true) ); + } + static int atoi(String a) { int i=0; try { -- cgit v1.2.3 From b738983638703bb721ee4c9820c8ef43e2252e73 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 24 Jan 2013 17:24:22 +0100 Subject: Bug 665 (part 1) - Allow dis-association of GLContext's GLDrawable .. Changes allowing re-association (incl. null) of GLContext/GLDrawable: - GLAutoDrawable: Refine API doc 'setContext(..)' - GLContext: Refine API doc: 'setGLDrawable(..)' 'getGLDrawable()' - GLContextImpl.setGLDrawable(): Handle null drawable - GLAutoDrawableDelegate/GLAutoDrawableBase: Allow null GLContext - GLDrawableHelper.switchContext(..)/recreateGLDrawable(): Balance GLContext.setGLDrawable(..) calls - New GLEventListenerState, holding state vector [GLEventListener, GLContext, .. ] impl. relocation of all components from/to GLAutoDrawable. - GLDrawableUtil - Using GLEventListenerState for swapGLContextAndAllGLEventListener(..) +++ NEWT Window*: - getDisplayHandle() is 'final', no more 'shortcut' code allowed due to re-association incl. display handle. - close*: - close config's device (was missing) - null config +++ Changes allowing reconfig of Display handle as required to re-associate pre-existing GLContext to a 'window': - AbstractGraphicsDevice: Add isHandleOwner() / clearHandleOwner() - Impl. in X11GraphicsDevice and EGLGraphicsDevice, NOP in DefaultGraphicsDevice - DefaultGraphicsConfiguration add 'setScreen(..)' - MutableGraphicsConfiguration - Make DefaultGraphicsConfiguration.setScreen(..) public - NativeWindowFactory add 'createScreen(String type, AbstractGraphicsDevice device, int screen)' - Refactored from SWTAccessor - NativeWindow x11ErrorHandler: Dump Stack Trace in DEBUG mode, always. --- make/scripts/tests-x64.bat | 3 +- make/scripts/tests.sh | 10 +- .../com/jogamp/opengl/GLAutoDrawableDelegate.java | 8 +- .../com/jogamp/opengl/util/GLDrawableUtil.java | 116 +------ .../classes/javax/media/opengl/GLAutoDrawable.java | 32 +- src/jogl/classes/javax/media/opengl/GLContext.java | 23 +- .../classes/jogamp/opengl/GLAutoDrawableBase.java | 13 +- src/jogl/classes/jogamp/opengl/GLContextImpl.java | 24 +- .../classes/jogamp/opengl/GLDrawableHelper.java | 31 +- .../jogamp/opengl/GLEventListenerState.java | 267 ++++++++++++++++ .../nativewindow/MutableGraphicsConfiguration.java | 7 + .../jogamp/nativewindow/egl/EGLGraphicsDevice.java | 11 +- .../com/jogamp/nativewindow/swt/SWTAccessor.java | 19 +- .../jogamp/nativewindow/x11/X11GraphicsDevice.java | 12 +- .../AbstractGraphicsConfiguration.java | 3 +- .../media/nativewindow/AbstractGraphicsDevice.java | 12 +- .../media/nativewindow/AbstractGraphicsScreen.java | 2 + .../nativewindow/DefaultGraphicsConfiguration.java | 17 +- .../media/nativewindow/DefaultGraphicsDevice.java | 19 +- .../media/nativewindow/DefaultGraphicsScreen.java | 6 +- .../media/nativewindow/NativeWindowFactory.java | 27 ++ src/nativewindow/native/x11/Xmisc.c | 2 +- .../classes/com/jogamp/newt/opengl/GLWindow.java | 18 +- src/newt/classes/jogamp/newt/WindowImpl.java | 9 +- .../jogamp/newt/driver/x11/WindowDriver.java | 10 +- .../acore/TestGLContextDrawableSwitch01NEWT.java | 330 +++++++++++++++++++ .../acore/TestGLContextDrawableSwitch11NEWT.java | 352 +++++++++++++++++++++ .../acore/TestGLContextDrawableSwitchNEWT.java | 310 ------------------ .../test/junit/util/GLEventListenerCounter.java | 65 ++++ 29 files changed, 1222 insertions(+), 536 deletions(-) create mode 100644 src/jogl/classes/jogamp/opengl/GLEventListenerState.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/util/GLEventListenerCounter.java (limited to 'src/nativewindow/native/x11') diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat index b66f8b8ab..8bee4c6dd 100755 --- a/make/scripts/tests-x64.bat +++ b/make/scripts/tests-x64.bat @@ -12,7 +12,8 @@ REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedCon REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile02NEWT %* -REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT %* +scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT %* +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch11NEWT %* REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT %* REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGPUMemSec01NEWT %* diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 80e418056..9625519b9 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -89,6 +89,7 @@ function jrun() { #D_ARGS="-Djogl.debug.FBObject" #D_ARGS="-Djogl.debug.GLSLCode" #D_ARGS="-Djogl.debug.GLSLCode -Djogl.debug.DebugGL -Djogl.debug.TraceGL" + #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLContext.TraceSwitch" #D_ARGS="-Djogl.debug.GLContext.TraceSwitch" #D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLCode" #D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLState" @@ -105,6 +106,7 @@ function jrun() { #D_ARGS="-Djogamp.debug=all" #D_ARGS="-Djogamp.debug=all -Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all" #D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all" + #D_ARGS="-Dnativewindow.debug.X11Util" #D_ARGS="-Djogl.debug.Animator" #D_ARGS="-Djogl.debug=all -Dnewt.debug=all" #D_ARGS="-Djogl.debug.GLDrawable -Djogl.debug.GLContext -Djogl.debug.GLCanvas" @@ -284,7 +286,8 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch02NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLPointsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug651NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug658NEWT $* @@ -303,6 +306,9 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch11NEWT $* + #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer01GLCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer02NewtCanvasAWT $* @@ -399,7 +405,7 @@ function testawtswt() { # # newt.awt (testawt) # -testawt com.jogamp.opengl.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $* +#testawt com.jogamp.opengl.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper $* #testawt com.jogamp.opengl.test.junit.newt.TestEventSourceNotAWTBug #testawt com.jogamp.opengl.test.junit.newt.TestFocus01SwingAWTRobot $* diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java index 38a8deef8..38315dc72 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java +++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java @@ -65,7 +65,10 @@ import jogamp.opengl.GLDrawableImpl; public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAutoDrawable { /** * @param drawable a valid and already realized {@link GLDrawable} - * @param context a valid {@link GLContext}, may not be made current (created) yet. + * @param context a valid {@link GLContext}, + * may not have been made current (created) yet, + * may not be associated w/ drawable yet, + * may be null for lazy initialization * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}. * @param ownDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued, * otherwise pass false. Closing the device is required in case @@ -78,9 +81,6 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAuto if(null == drawable) { throw new IllegalArgumentException("null drawable"); } - if(null == context) { - throw new IllegalArgumentException("null context"); - } if(!drawable.isRealized()) { throw new IllegalArgumentException("drawable not realized"); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java index cc81e4820..c03e4bfa4 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java @@ -27,17 +27,14 @@ */ package com.jogamp.opengl.util; -import java.util.ArrayList; -import java.util.List; - import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLRunnable; import jogamp.opengl.Debug; +import jogamp.opengl.GLEventListenerState; /** * Providing utility functions dealing w/ {@link GLDrawable}s, {@link GLAutoDrawable} and their {@link GLEventListener}. @@ -83,7 +80,7 @@ public class GLDrawableUtil { dest.addGLEventListener(listener); if(preserveInitState && initialized) { dest.setGLEventListenerInitState(listener, true); - dest.invoke(false, new ReshapeGLEventListener(listener)); + dest.invoke(false, new GLEventListenerState.ReshapeGLEventListener(listener)); } // else .. !init state is default } @@ -121,108 +118,13 @@ public class GLDrawableUtil { * @param b */ public static final void swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b) { - final List aGLCmds = new ArrayList(); - final List bGLCmds = new ArrayList(); - final GLAnimatorControl aAnim = a.getAnimator(); - final GLAnimatorControl bAnim = b.getAnimator(); - final boolean aIsPaused = isAnimatorAnimatingOnOtherThread(aAnim) && aAnim.pause(); - final boolean bIsPaused = isAnimatorAnimatingOnOtherThread(bAnim) && bAnim.pause(); - - // - // remove and cache all GLEventListener and their init-state - // - final int aSz = a.getGLEventListenerCount(); - final GLEventListener[] aGLE = new GLEventListener[aSz]; - final boolean[] aInit = new boolean[aSz]; - for(int i=0; idrawable might be an inner GLDrawable instance if using a delegation pattern, - * or this GLAutoDrawable instance. + * Associate the new context, newtCtx, to this auto-drawable. *

- * If the old or new context was current on this thread, it is being released before switching the drawable. + * The current context will be dis-associated from this auto-drawable + * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first. + *

+ *

+ * The new context will be associated with this auto-drawable + * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}. + *

+ *

+ * If the old or new context was current on this thread, it is being released before switching the association. * The new context will be made current afterwards, if it was current before. * However the user shall take extra care that no other thread * attempts to make this context current. *

*

- * Be aware that the old context is still bound to the drawable, - * and that one context can only be bound to one drawable at one time! - *

- *

* In case you do not intend to use the old context anymore, i.e. - * not assigning it to another drawable, it shall be - * destroyed before setting the new context, i.e.: + * not assigning it to another drawable, it shall be + * destroyed, i.e.: *

-            GLContext oldCtx = glad.getContext();
+            GLContext oldCtx = glad.setContext(newCtx);
             if(null != oldCtx) {
                 oldCtx.destroy();
             }
-            glad.setContext(newCtx);            
    * 
- * This is required, since a context must have a valid drawable at all times - * and this API shall not restrict the user in any way. *

* - * @param newCtx the new context - * @return the replaced GLContext, maybe null + * @param newCtx the new context, maybe null for dis-association. + * @return the previous GLContext, maybe null * * @see GLContext#setGLDrawable(GLDrawable, boolean) * @see GLContext#setGLReadDrawable(GLDrawable) diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 455f2d70d..4817add4d 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -217,15 +217,20 @@ public abstract class GLContext { /** * Sets the read/write drawable for framebuffer operations. *

+ * If the arguments reflect the current state of this context + * this method is a no-operation and returns the old and current {@link GLDrawable}. + *

+ *

* If the context was current on this thread, it is being released before switching the drawable * and made current afterwards. However the user shall take extra care that not other thread * attempts to make this context current. Otherwise a race condition may happen. *

- * @param readWrite the read/write drawable for framebuffer operations. - * @param setWriteOnly if true and if the current read-drawable differs - * from the write-drawable ({@link #setGLReadDrawable(GLDrawable)}), - * only change the write-drawable. Otherwise set both drawables. - * @return the replaced read/write drawable + * @param readWrite The read/write drawable for framebuffer operations, maybe null to remove association. + * @param setWriteOnly Only change the write-drawable, if setWriteOnly is true and + * if the {@link #getGLReadDrawable() read-drawable} differs + * from the {@link #getGLDrawable() write-drawable}. + * Otherwise set both drawables, read and write. + * @return The previous read/write drawable * * @throws GLException in case null is being passed or * this context is made current on another thread. @@ -239,6 +244,12 @@ public abstract class GLContext { /** * Returns the write-drawable this context uses for framebuffer operations. + *

+ * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)}, + * it equals to the write-drawable (default). + *

+ * @see #setGLDrawable(GLDrawable, boolean) + * @see #setGLReadDrawable(GLDrawable) */ public abstract GLDrawable getGLDrawable(); @@ -259,7 +270,7 @@ public abstract class GLContext { * * @param read the read-drawable for read framebuffer operations. * If null is passed, the default write drawable will be set. - * @return the replaced read-drawable + * @return the previous read-drawable * * @throws GLException in case a read drawable is not supported or * this context is made current on another thread. diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index eadd59559..c20197e72 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -74,8 +74,12 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking /** - * @param drawable upstream {@link GLDrawableImpl} instance, may be null for lazy initialization - * @param context upstream {@link GLContextImpl} instance, may be null for lazy initialization + * @param drawable upstream {@link GLDrawableImpl} instance, + * may be null for lazy initialization + * @param context upstream {@link GLContextImpl} instance, + * may not have been made current (created) yet, + * may not be associated w/ drawable yet, + * may be null for lazy initialization * @param ownsDevice pass true if {@link AbstractGraphicsDevice#close()} shall be issued, * otherwise pass false. Closing the device is required in case * the drawable is created w/ it's own new instance, e.g. offscreen drawables, @@ -85,6 +89,9 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { this.drawable = drawable; this.context = context; this.ownsDevice = ownsDevice; + if(null != context && null != drawable) { + context.setGLDrawable(drawable, false); + } resetFPSCounter(); } @@ -326,7 +333,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { final GLContext oldCtx = context; final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; - if(newCtxCurrent) { + if(newCtxCurrent) { // implies null != newCtx context.makeCurrent(); } return oldCtx; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index f2c2cfada..2a2b6a8fd 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -203,8 +203,8 @@ public abstract class GLContextImpl extends GLContext { @Override public final GLDrawable setGLDrawable(GLDrawable readWrite, boolean setWriteOnly) { - if(null==readWrite) { - throw new GLException("Null read/write drawable not allowed"); + if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) { + return drawable; // no change. } final boolean lockHeld = lock.isOwner(Thread.currentThread()); if(lockHeld) { @@ -212,16 +212,20 @@ public abstract class GLContextImpl extends GLContext { } else if(lock.isLockedByOtherThread()) { // still could glitch .. throw new GLException("GLContext current by other thread ("+lock.getOwner()+"), operation not allowed."); } - if(!setWriteOnly || drawableRead==drawable) { // if !setWriteOnly || !explicitReadDrawable + if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable drawableRead = (GLDrawableImpl) readWrite; } final GLDrawableImpl old = drawable; - old.associateContext(this, false); - drawableRetargeted = null != drawable; + if( null != old ) { + old.associateContext(this, false); + } + drawableRetargeted |= null != drawable && readWrite != drawable; drawable = (GLDrawableImpl) readWrite ; - drawable.associateContext(this, true); - if(lockHeld) { - makeCurrent(); + if( null != drawable ) { + drawable.associateContext(this, true); + if( lockHeld ) { + makeCurrent(); + } } return old; } @@ -334,7 +338,7 @@ public abstract class GLContextImpl extends GLContext { ", surf "+toHexString(drawable.getHandle())+", isShared "+GLContextShareSet.isShared(this)+" - "+lock); } if (contextHandle != 0) { - int lockRes = drawable.lockSurface(); + final int lockRes = drawable.lockSurface(); if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { // this would be odd .. throw new GLException("Surface not ready to lock: "+drawable); @@ -408,7 +412,7 @@ public abstract class GLContextImpl extends GLContext { throw new GLException("Destination OpenGL context has not been created"); } - int lockRes = drawable.lockSurface(); + final int lockRes = drawable.lockSurface(); if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { // this would be odd .. throw new GLException("Surface not ready to lock"); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index f8c58ee34..5d113ff83 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -131,30 +131,36 @@ public class GLDrawableHelper { } /** - * Associate a new context to the drawable and also propagates the context/drawable switch by - * calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}. - *

- * If the old or new context was current on this thread, it is being released before switching the drawable. + * Switch {@link GLContext} / {@link GLDrawable} association. + *

+ * Dis-associate oldCtx from drawable + * via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);}. *

*

- * Be aware that the old context is still bound to the drawable, - * and that one context can only bound to one drawable at one time! + * Re-associate newCtx with drawable + * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}. + *

+ *

+ * If the old or new context was current on this thread, it is being released before switching the drawable. *

*

* No locking is being performed on the drawable, caller is required to take care of it. *

* * @param drawable the drawable which context is changed - * @param oldCtx the old context - * @param newCtx the new context + * @param oldCtx the old context, maybe null. + * @param newCtx the new context, maybe null for dis-association. * @param newCtxCreationFlags additional creation flags if newCtx is not null and not been created yet, see {@link GLContext#setContextCreationFlags(int)} * @return true if the new context was current, otherwise false * * @see GLAutoDrawable#setContext(GLContext) */ public static final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int newCtxCreationFlags) { - if( null != oldCtx && oldCtx.isCurrent() ) { - oldCtx.release(); + if( null != oldCtx ) { + if( oldCtx.isCurrent() ) { + oldCtx.release(); + } + oldCtx.setGLDrawable(null, true); // dis-associate old pair } final boolean newCtxCurrent; if(null!=newCtx) { @@ -163,8 +169,8 @@ public class GLDrawableHelper { newCtx.release(); } newCtx.setContextCreationFlags(newCtxCreationFlags); - newCtx.setGLDrawable(drawable, true); // propagate context/drawable switch - } else { + newCtx.setGLDrawable(drawable, true); // re-associate new pair + } else { newCtxCurrent = false; } return newCtxCurrent; @@ -203,6 +209,7 @@ public class GLDrawableHelper { } context.getGL().glFinish(); context.release(); + context.setGLDrawable(null, true); // dis-associate } if(null != proxySurface) { diff --git a/src/jogl/classes/jogamp/opengl/GLEventListenerState.java b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java new file mode 100644 index 000000000..dea2bc85b --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java @@ -0,0 +1,267 @@ +/** + * Copyright 2013 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.opengl; + +import java.util.ArrayList; +import java.util.List; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.VisualIDHolder; +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLRunnable; + +import com.jogamp.nativewindow.MutableGraphicsConfiguration; + +/** + * GLEventListenerState is holding {@link GLAutoDrawable} components crucial + * to relocating all its {@link GLEventListener} w/ their operating {@link GLContext}, etc. + * The components are: + *
    + *
  • {@link AbstractGraphicsScreen}
  • + *
  • {@link GLCapabilitiesImmutable}
  • + *
  • {@link GLContext} operating all {@link GLEventListener}
  • + *
  • All {@link GLEventListener}
  • + *
  • All {@link GLEventListener}'s init state
  • + *
  • {@link GLAnimatorControl}
  • + *
+ *

+ * A GLEventListenerState instance can be created while components are {@link #moveFrom(GLAutoDrawable) moved from} a {@link GLAutoDrawable} + * to the new instance, which gains {@link #isOwner() ownership} of the moved components. + *

+ *

+ * A GLEventListenerState instance's components can be {@link #moveTo(GLAutoDrawable) moved to} a {@link GLAutoDrawable}, + * while loosing {@link #isOwner() ownership} of the moved components. + *

+ *

+ */ +public class GLEventListenerState { + private GLEventListenerState(AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, GLContext context, int count, GLAnimatorControl anim) { + this.screen = screen; + this.caps = caps; + this.context = context; + this.listeners = new GLEventListener[count]; + this.listenersInit = new boolean[count]; + this.anim = anim; + this.owner = true; + } + /** + * Returns true, if this instance is the current owner of the components, + * otherwise false. + *

+ * Ownership is lost if {@link #moveTo(GLAutoDrawable)} is being called successfully + * and all components are transferred to the new {@link GLAutoDrawable}. + *

+ */ + public final boolean isOwner() { return owner; } + + public final int listenerCount() { return listeners.length; } + + public final AbstractGraphicsScreen screen; + public final GLCapabilitiesImmutable caps; + public final GLContext context; + public final GLEventListener[] listeners; + public final boolean[] listenersInit; + public final GLAnimatorControl anim; + + private boolean owner; + + /** + * Last resort to destroy and loose ownership + */ + public void destroy() { + if( owner ) { + final int aSz = listenerCount(); + for(int i=0; i + * Note that all components are removed from the {@link GLAutoDrawable}, + * i.e. the {@link GLContext}, all {@link GLEventListener}. + *

+ *

+ * If the {@link GLAutoDrawable} was added to a {@link GLAnimatorControl}, it is removed + * and the {@link GLAnimatorControl} added to the GLEventListenerState. + *

+ *

+ * The returned GLEventListenerState instance is the {@link #isOwner() owner of the components}. + *

+ * + * @param a {@link GLAutoDrawable} source to move components from + * @return new GLEventListenerState instance {@link #isOwner() owning} moved components. + * + * @see #moveTo(GLAutoDrawable) + */ + public static GLEventListenerState moveFrom(GLAutoDrawable a) { + final int aSz = a.getGLEventListenerCount(); + + // Create new AbstractGraphicsScreen w/ cloned AbstractGraphicsDevice for future GLAutoDrawable + // allowing this AbstractGraphicsDevice to loose ownership -> not closing display/device! + final AbstractGraphicsConfiguration aCfg1 = a.getNativeSurface().getGraphicsConfiguration(); + final GLCapabilitiesImmutable caps1 = (GLCapabilitiesImmutable) aCfg1.getChosenCapabilities(); + final AbstractGraphicsScreen aScreen1 = aCfg1.getScreen(); + final AbstractGraphicsDevice aDevice1 = aScreen1.getDevice(); + final AbstractGraphicsDevice aDevice2 = (AbstractGraphicsDevice) aDevice1.clone(); + final AbstractGraphicsScreen aScreen2 = NativeWindowFactory.createScreen( NativeWindowFactory.getNativeWindowType(false), aDevice2, aScreen1.getIndex() ); + + final GLAnimatorControl aAnim = a.getAnimator(); + if( null != aAnim ) { + aAnim.remove(a); // also handles ECT + } + + final GLEventListenerState glls = new GLEventListenerState(aScreen2, caps1, a.getContext(), aSz, aAnim); + + // + // remove and cache all GLEventListener and their init-state + // + for(int i=0; i + * If the previous {@link GLAutoDrawable} was removed from a {@link GLAnimatorControl} by previous {@link #moveFrom(GLAutoDrawable)}, + * the given {@link GLAutoDrawable} is added to the cached {@link GLAnimatorControl}. + * This operation is skipped, if the given {@link GLAutoDrawable} is already added to a {@link GLAnimatorControl} instance. + *

+ *

+ * Note: After this operation, the GLEventListenerState reference should be released. + *

+ * + * @param a {@link GLAutoDrawable} destination to move GLEventListenerState components to + * + * @throws GLException if the {@link GLAutoDrawable}'s configuration is incompatible, i.e. different {@link GLCapabilitiesImmutable}. + * + * @see #moveFrom(GLAutoDrawable) + * @see #isOwner() + */ + public final void moveTo(GLAutoDrawable a) { + final List aGLCmds = new ArrayList(); + final int aSz = listenerCount(); + + final MutableGraphicsConfiguration aCfg = (MutableGraphicsConfiguration) a.getNativeSurface().getGraphicsConfiguration(); + final GLCapabilitiesImmutable aCaps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities(); + if( caps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) != aCaps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) ) { + throw new GLException("XXX: Incompatible - Prev Holder: "+caps+", New Holder "+caps); + } + final GLContext prevContext = a.getContext(); + if( null != prevContext) { + prevContext.destroy(); + } + final AbstractGraphicsScreen preScreen = aCfg.getScreen(); + aCfg.setScreen( screen ); + preScreen.getDevice().close(); + a.setContext( context ); + owner = false; + + // + // Trigger GL-Viewport reset and reshape of all initialized GLEventListeners + // + aGLCmds.add(setViewport); + for(int i=0; i= 0 is specific screen * @return - * @throws UnsupportedOperationException */ - public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) throws UnsupportedOperationException { - if( isX11 ) { - X11GraphicsDevice x11Device = (X11GraphicsDevice)device; - if(0 > screen) { - screen = x11Device.getDefaultScreen(); - } - return new X11GraphicsScreen(x11Device, screen); - } - if(0 > screen) { - screen = 0; // FIXME: Needs native API utilization - } - if( isWindows || isOSX ) { - return new DefaultGraphicsScreen(device, screen); - } - throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) { + return NativeWindowFactory.createScreen(nwt, device, screen); } public static int getNativeVisualID(AbstractGraphicsDevice device, long windowHandle) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java index 0f28ca67c..da3b31de4 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java @@ -45,7 +45,7 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - final boolean handleOwner; + /* final */ boolean handleOwner; final boolean isXineramaEnabled; /** Constructs a new X11GraphicsDevice corresponding to the given connection and default @@ -153,5 +153,13 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } return super.close(); } + + @Override + public boolean isHandleOwner() { + return handleOwner; + } + @Override + public void clearHandleOwner() { + handleOwner = false; + } } - diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java index ebdaf2fbb..4e45113d4 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java @@ -42,8 +42,9 @@ package javax.media.nativewindow; /** A marker interface describing a graphics configuration, visual, or pixel format in a toolkit-independent manner. */ - public interface AbstractGraphicsConfiguration extends VisualIDHolder, Cloneable { + public Object clone(); + /** * Return the screen this graphics configuration is valid for */ diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 8ecd5242d..585cd1f09 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -45,7 +45,6 @@ import jogamp.nativewindow.Debug; /** A interface describing a graphics device in a toolkit-independent manner. */ - public interface AbstractGraphicsDevice extends Cloneable { public static final boolean DEBUG = Debug.debug("GraphicsDevice"); @@ -58,6 +57,8 @@ public interface AbstractGraphicsDevice extends Cloneable { /** Default unit id for the 1st device: 0 */ public static int DEFAULT_UNIT = 0; + public Object clone(); + /** * Returns the type of the underlying subsystem, ie * NativeWindowFactory.TYPE_KD, NativeWindowFactory.TYPE_X11, .. @@ -143,10 +144,17 @@ public interface AbstractGraphicsDevice extends Cloneable { *

* Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} - * issue the native close operation or skip it depending on the handles's ownership. + * issue the native close operation or skip it depending on the {@link #isHandleOwner() handles's ownership}. *

* * @return true if the handle was not null and closing was successful, otherwise false. */ public boolean close(); + + /** + * @return true if instance owns the handle to issue {@link #close()}, otherwise false. + */ + public boolean isHandleOwner(); + + public void clearHandleOwner(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java index eb2cc9120..acb98073b 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java @@ -44,6 +44,8 @@ package javax.media.nativewindow; */ public interface AbstractGraphicsScreen extends Cloneable { + public Object clone(); + /** * Return the device this graphics configuration is valid for */ diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java index a33c3792a..6b23172e1 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java @@ -93,25 +93,26 @@ public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphics /** * Set the capabilities to a new value. * + *

* The use case for setting the Capabilities at a later time is - * a change of the graphics device in a multi-screen environment.
- * + * a change or re-validation of capabilities. + *

* @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ protected void setChosenCapabilities(CapabilitiesImmutable capsChosen) { - capabilitiesChosen = capsChosen; + this.capabilitiesChosen = capsChosen; } /** * Set a new screen. * + *

* the use case for setting a new screen at a later time is - * a change of the graphics device in a multi-screen environment.
- * - * A copy of the passed object is being used. + * a change of the graphics device in a multi-screen environment. + *

*/ - final protected void setScreen(DefaultGraphicsScreen screen) { - this.screen = (AbstractGraphicsScreen) screen.clone(); + protected void setScreen(AbstractGraphicsScreen screen) { + this.screen = screen; } @Override diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index 9288652d9..b3ae4628c 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -37,10 +37,10 @@ import jogamp.nativewindow.NativeWindowFactoryImpl; public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice { private static final String separator = "_"; - private String type; - protected String connection; - protected int unitID; - protected String uniqueID; + private final String type; + protected final String connection; + protected final int unitID; + protected final String uniqueID; protected long handle; protected ToolkitLock toolkitLock; @@ -170,9 +170,18 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice return false; } + @Override + public boolean isHandleOwner() { + return false; + } + + @Override + public void clearHandleOwner() { + } + @Override public String toString() { - return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", "+toolkitLock+"]"; + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", owner "+isHandleOwner()+", "+toolkitLock+"]"; } /** diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java index f50bd0e14..9fa58c7a3 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java @@ -33,8 +33,8 @@ package javax.media.nativewindow; public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen { - AbstractGraphicsDevice device; - private int idx; + private final AbstractGraphicsDevice device; + private final int idx; public DefaultGraphicsScreen(AbstractGraphicsDevice device, int idx) { this.device = device; @@ -57,7 +57,7 @@ public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen public AbstractGraphicsDevice getDevice() { return device; } - + public int getIndex() { return idx; } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index d7f28a986..07702c762 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -48,6 +48,10 @@ import jogamp.nativewindow.ResourceToolkitLock; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.nativewindow.awt.AWTGraphicsDevice; +import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsScreen; /** Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the {@link NativeWindow} interface, @@ -428,6 +432,29 @@ public abstract class NativeWindowFactory { return NativeWindowFactoryImpl.getNullToolkitLock(); } + /** + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return newly created AbstractGraphicsScreen of given native type + */ + public static AbstractGraphicsScreen createScreen(String type, AbstractGraphicsDevice device, int screen) { + if( TYPE_X11 == type ) { + final X11GraphicsDevice x11Device = (X11GraphicsDevice)device; + if(0 > screen) { + screen = x11Device.getDefaultScreen(); + } + return new X11GraphicsScreen(x11Device, screen); + } + if(0 > screen) { + screen = 0; // FIXME: Needs native API utilization + } + if( TYPE_AWT == type ) { + final AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) device; + return new AWTGraphicsScreen(awtDevice); + } + return new DefaultGraphicsScreen(device, screen); + } + /** Returns the appropriate NativeWindowFactory to handle window objects of the given type. The windowClass might be {@link NativeWindow NativeWindow}, in which case the client has diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index a8d45f288..017c52df2 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -180,7 +180,7 @@ static int errorHandlerThrowException = 0; static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { - if(!errorHandlerQuiet) { + if( !errorHandlerQuiet || errorHandlerDebug ) { const char * errnoStr = strerror(errno); char errCodeStr[80]; char reqCodeStr[80]; diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 96d0f6e3b..7fccb6622 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -458,24 +458,22 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind } else { t0 = 0; } - - /* if (nativeWindowCreated && null != context) { - throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)"); - } */ - if (null == context && visible && 0 != window.getWindowHandle() && 0 ctx1/draw2, ctx2/draw1. + */ +public class TestGLContextDrawableSwitch01NEWT extends UITestCase { + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + + @BeforeClass + public static void initClass() { + glp = GLProfile.getGL2ES2(); + caps = new GLCapabilities(glp); + width = 256; + height = 256; + } + + private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + final GLContext context = drawable.createContext(null); + Assert.assertNotNull(context); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); + window.destroy(); // destroys the actual window + } + }; + + // add basic window interaction + window.addWindowListener(new WindowAdapter() { + @Override + public void windowRepaint(WindowUpdateEvent e) { + glad.windowRepaintOp(); + } + @Override + public void windowResized(WindowEvent e) { + glad.windowResizedOp(window.getWidth(), window.getHeight()); + } + @Override + public void windowDestroyNotify(WindowEvent e) { + glad.windowDestroyNotifyOp(); + } + }); + window.addWindowListener(wl); + + return glad; + } + + @Test(timeout=30000) + public void testSwitch2WindowSingleContext() throws InterruptedException { + final QuitAdapter quitAdapter = new QuitAdapter(); + + GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter); + GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter); + + // create single context using glad1 and assign it to glad1, + // destroy the prev. context afterwards. + { + final GLContext newCtx = glad1.createContext(null); + Assert.assertNotNull(newCtx); + final GLContext oldCtx = glad1.setContext(newCtx); + Assert.assertNotNull(oldCtx); + oldCtx.destroy(); + final int res = newCtx.makeCurrent(); + Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); + newCtx.release(); + } + + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + GearsES2 gears = new GearsES2(1); + glad1.addGLEventListener(gears); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + Animator animator = new Animator(); + animator.add(glad1); + animator.add(glad2); + animator.start(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + + // switch context _and_ the demo synchronously + GLDrawableUtil.swapGLContextAndAllGLEventListener(glad1, glad2); + + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + glad1.destroy(); + glad2.destroy(); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowOneDemo() throws InterruptedException { + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GearsES2 gears = new GearsES2(1); + final QuitAdapter quitAdapter = new QuitAdapter(); + + GLWindow glWindow1 = GLWindow.create(caps); + glWindow1.setTitle("win1"); + glWindow1.setSize(width, height); + glWindow1.setPosition(64, 64); + glWindow1.addGLEventListener(0, gears); + glWindow1.addGLEventListener(snapshotGLEventListener); + glWindow1.addWindowListener(quitAdapter); + + GLWindow glWindow2 = GLWindow.create(caps); + glWindow2.setTitle("win2"); + glWindow2.setSize(width+100, height+100); + glWindow2.setPosition(2*64+width, 64); + glWindow2.addWindowListener(quitAdapter); + + Animator animator = new Animator(); + animator.add(glWindow1); + animator.add(glWindow2); + animator.start(); + + glWindow1.setVisible(true); + glWindow2.setVisible(true); + + snapshotGLEventListener.setMakeSnapshot(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + + // switch context _and_ the demo synchronously + GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); + + System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + + snapshotGLEventListener.setMakeSnapshot(); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + glWindow1.destroy(); + glWindow2.destroy(); + + } + + @Test(timeout=30000) + public void testSwitch2GLWindowEachWithOwnDemo() throws InterruptedException { + final GearsES2 gears = new GearsES2(1); + final RedSquareES2 rsquare = new RedSquareES2(1); + final QuitAdapter quitAdapter = new QuitAdapter(); + final SnapshotGLEventListener snapshotGLEventListener1 = new SnapshotGLEventListener(); + final SnapshotGLEventListener snapshotGLEventListener2 = new SnapshotGLEventListener(); + + GLWindow glWindow1 = GLWindow.create(caps); + glWindow1.setTitle("win1"); + glWindow1.setSize(width, height); + glWindow1.setPosition(64, 64); + glWindow1.addGLEventListener(0, gears); + glWindow1.addGLEventListener(snapshotGLEventListener1); + glWindow1.addWindowListener(quitAdapter); + + GLWindow glWindow2 = GLWindow.create(caps); + glWindow2.setTitle("win2"); + glWindow2.setSize(width+100, height+100); + glWindow2.setPosition(2*64+width, 64); + glWindow2.addGLEventListener(0, rsquare); + glWindow2.addGLEventListener(snapshotGLEventListener2); + glWindow2.addWindowListener(quitAdapter); + + Animator animator = new Animator(); + animator.add(glWindow1); + animator.add(glWindow2); + animator.start(); + + glWindow1.setVisible(true); + glWindow2.setVisible(true); + + snapshotGLEventListener1.setMakeSnapshot(); + snapshotGLEventListener2.setMakeSnapshot(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); + System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + snapshotGLEventListener1.setMakeSnapshot(); + snapshotGLEventListener2.setMakeSnapshot(); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + // System.err.println("pre -del-w1: w1: "+glWindow1); + // System.err.println("pre -del-w1: w2: "+glWindow2); + glWindow1.destroy(); + // System.err.println("post-del-w1: w1: "+glWindow1); + // System.err.println("post-del-w1: w2: "+glWindow2); + glWindow2.destroy(); + + } + + // default timing for 2 switches + static long duration = 2200; // ms + static long period = 1000; // ms + + public static void main(String args[]) throws IOException { + for(int i=0; i + * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *

+ */ +public class TestGLContextDrawableSwitch11NEWT extends UITestCase { + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + + @BeforeClass + public static void initClass() { + glp = GLProfile.getGL2ES2(); + caps = new GLCapabilities(glp); + width = 256; + height = 256; + } + + private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); + window.destroy(); // destroys the actual window + } + }; + + // add basic window interaction + window.addWindowListener(new WindowAdapter() { + @Override + public void windowRepaint(WindowUpdateEvent e) { + glad.windowRepaintOp(); + } + @Override + public void windowResized(WindowEvent e) { + glad.windowResizedOp(window.getWidth(), window.getHeight()); + } + @Override + public void windowDestroyNotify(WindowEvent e) { + glad.windowDestroyNotifyOp(); + } + }); + window.addWindowListener(wl); + + return glad; + } + + @Test(timeout=30000) + public void test01() throws InterruptedException { + final QuitAdapter quitAdapter = new QuitAdapter(); + + final GLEventListenerCounter glelCounter = new GLEventListenerCounter(); + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final Animator animator = new Animator(); + animator.start(); + + final long t0 = System.currentTimeMillis(); + final GLEventListenerState glls1; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + final GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter); + final GLContext context1 = glad1.createContext(null); + glad1.setContext(context1); + animator.add(glad1); + + glad1.addGLEventListener(glelCounter); + glad1.addGLEventListener(new GearsES2(1)); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + long t1 = System.currentTimeMillis(); + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + // - dis-associate context from glad1 + // - destroy glad1 + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(context1, glad1.getContext()); + Assert.assertEquals(3, glad1.getGLEventListenerCount()); + Assert.assertEquals(context1.getGLReadDrawable(), glad1.getDelegatedDrawable()); + Assert.assertEquals(context1.getGLDrawable(), glad1.getDelegatedDrawable()); + + glls1 = GLEventListenerState.moveFrom(glad1); + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(context1, glls1.context); + Assert.assertNull(context1.getGLReadDrawable()); + Assert.assertNull(context1.getGLDrawable()); + Assert.assertEquals(3, glls1.listenerCount()); + Assert.assertEquals(true, glls1.isOwner()); + Assert.assertEquals(null, glad1.getContext()); + Assert.assertEquals(0, glad1.getGLEventListenerCount()); + + glad1.destroy(); + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + } + + // - create glad2 w/ survived context + { + final GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter); + snapshotGLEventListener.setMakeSnapshot(); + + Assert.assertEquals(null, glad2.getContext()); + Assert.assertEquals(0, glad2.getGLEventListenerCount()); + + glls1.moveTo(glad2); + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(glls1.context, glad2.getContext()); + Assert.assertEquals(3, glad2.getGLEventListenerCount()); + Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(false, glls1.isOwner()); + + long t1 = System.currentTimeMillis(); + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/1 ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + glad2.destroy(); + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(1, glelCounter.disposeCount); + } + animator.stop(); + } + + @Test(timeout=30000) + public void test02() throws InterruptedException { + final QuitAdapter quitAdapter = new QuitAdapter(); + + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final long t0 = System.currentTimeMillis(); + final GLEventListenerState glls1; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + final GLWindow glad1 = GLWindow.create(caps); + glad1.setSize(width, height); + glad1.setPosition(64, 64); + glad1.addWindowListener(quitAdapter); + glad1.setVisible(true); + animator.add(glad1); + + glad1.addGLEventListener(glelTracker); + glad1.addGLEventListener(new GearsES2(1)); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + long t1 = System.currentTimeMillis(); + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + // - dis-associate context from glad1 + // - destroy glad1 + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + Assert.assertEquals(3, glad1.getGLEventListenerCount()); + Assert.assertEquals(glad1.getContext().getGLReadDrawable(), glad1.getDelegatedDrawable()); + Assert.assertEquals(glad1.getContext().getGLDrawable(), glad1.getDelegatedDrawable()); + + final GLContext context1 = glad1.getContext(); + glls1 = GLEventListenerState.moveFrom(glad1); + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + Assert.assertEquals(context1, glls1.context); + Assert.assertNull(context1.getGLReadDrawable()); + Assert.assertNull(context1.getGLDrawable()); + Assert.assertEquals(3, glls1.listenerCount()); + Assert.assertEquals(true, glls1.isOwner()); + Assert.assertEquals(null, glad1.getContext()); + Assert.assertEquals(0, glad1.getGLEventListenerCount()); + + glad1.destroy(); + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + } + + // - create glad2 w/ survived context + { + final GLWindow glad2 = GLWindow.create(caps); + glad2.setSize(width+100, height+100); + glad2.setPosition(2*64+width, 64); + glad2.addWindowListener(quitAdapter); + glad2.setVisible(true); + snapshotGLEventListener.setMakeSnapshot(); + + Assert.assertNotNull(glad2.getContext()); + Assert.assertEquals(0, glad2.getGLEventListenerCount()); + + glls1.moveTo(glad2); + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + Assert.assertEquals(glls1.context, glad2.getContext()); + Assert.assertEquals(3, glad2.getGLEventListenerCount()); + Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(false, glls1.isOwner()); + + long t1 = System.currentTimeMillis(); + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/1 ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + glad2.destroy(); + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(1, glelTracker.disposeCount); + } + animator.stop(); + } + + // default timing for 2 switches + static long duration = 2200; // ms + + public static void main(String args[]) throws IOException { + for(int i=0; i s) { - s++; - System.err.println(s+" - switch - START "+ ( t1 - t0 )); - - // switch context _and_ the demo synchronously - GLDrawableUtil.swapGLContextAndAllGLEventListener(glad1, glad2); - - System.err.println(s+" - switch - END "+ ( t1 - t0 )); - } - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - animator.stop(); - glad1.destroy(); - glad2.destroy(); - } - - @Test(timeout=30000) - public void testSwitch2GLWindowOneDemo() throws InterruptedException { - GearsES2 gears = new GearsES2(1); - final QuitAdapter quitAdapter = new QuitAdapter(); - - GLWindow glWindow1 = GLWindow.create(caps); - glWindow1.setTitle("win1"); - glWindow1.setSize(width, height); - glWindow1.setPosition(64, 64); - glWindow1.addGLEventListener(0, gears); - glWindow1.addWindowListener(quitAdapter); - - GLWindow glWindow2 = GLWindow.create(caps); - glWindow2.setTitle("win2"); - glWindow2.setSize(width+100, height+100); - glWindow2.setPosition(2*64+width, 64); - glWindow2.addWindowListener(quitAdapter); - - Animator animator = new Animator(); - animator.add(glWindow1); - animator.add(glWindow2); - animator.start(); - - glWindow1.setVisible(true); - glWindow2.setVisible(true); - - int s = 0; - long t0 = System.currentTimeMillis(); - long t1 = t0; - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { - if( ( t1 - t0 ) / period > s) { - s++; - System.err.println(s+" - switch - START "+ ( t1 - t0 )); - System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - - // switch context _and_ the demo synchronously - GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); - - System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - System.err.println(s+" - switch - END "+ ( t1 - t0 )); - } - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - animator.stop(); - glWindow1.destroy(); - glWindow2.destroy(); - - } - - @Test(timeout=30000) - public void testSwitch2GLWindowEachWithOwnDemo() throws InterruptedException { - GearsES2 gears = new GearsES2(1); - RedSquareES2 rsquare = new RedSquareES2(1); - final QuitAdapter quitAdapter = new QuitAdapter(); - - GLWindow glWindow1 = GLWindow.create(caps); - glWindow1.setTitle("win1"); - glWindow1.setSize(width, height); - glWindow1.setPosition(64, 64); - glWindow1.addGLEventListener(0, gears); - glWindow1.addWindowListener(quitAdapter); - - GLWindow glWindow2 = GLWindow.create(caps); - glWindow2.setTitle("win2"); - glWindow2.setSize(width+100, height+100); - glWindow2.setPosition(2*64+width, 64); - glWindow2.addGLEventListener(0, rsquare); - glWindow2.addWindowListener(quitAdapter); - - Animator animator = new Animator(); - animator.add(glWindow1); - animator.add(glWindow2); - animator.start(); - - glWindow1.setVisible(true); - glWindow2.setVisible(true); - - int s = 0; - long t0 = System.currentTimeMillis(); - long t1 = t0; - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { - if( ( t1 - t0 ) / period > s) { - s++; - System.err.println(s+" - switch - START "+ ( t1 - t0 )); - System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); - System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - System.err.println(s+" - switch - END "+ ( t1 - t0 )); - } - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - animator.stop(); - // System.err.println("pre -del-w1: w1: "+glWindow1); - // System.err.println("pre -del-w1: w2: "+glWindow2); - glWindow1.destroy(); - // System.err.println("post-del-w1: w1: "+glWindow1); - // System.err.println("post-del-w1: w2: "+glWindow2); - glWindow2.destroy(); - - } - - // default timing for 2 switches - static long duration = 2200; // ms - static long period = 1000; // ms - - public static void main(String args[]) throws IOException { - for(int i=0; i Date: Mon, 18 Mar 2013 08:16:25 +0100 Subject: NativeWindow OSXUtil RunOnMainThread: Use daemon attachment and do not detach; Add RunLater0(..) --- src/nativewindow/native/NativewindowCommon.c | 9 +++- src/nativewindow/native/NativewindowCommon.h | 2 +- src/nativewindow/native/macosx/OSXmisc.m | 65 ++++++++++++++++++---------- src/nativewindow/native/x11/Xmisc.c | 4 +- 4 files changed, 53 insertions(+), 27 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/NativewindowCommon.c b/src/nativewindow/native/NativewindowCommon.c index d2fdd5d69..e909c0494 100644 --- a/src/nativewindow/native/NativewindowCommon.c +++ b/src/nativewindow/native/NativewindowCommon.c @@ -74,7 +74,7 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) return strChars; } -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached) { +JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; @@ -83,7 +83,12 @@ JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { + if( asDaemon ) { + envRes = (*jvmHandle)->AttachCurrentThreadAsDaemon(jvmHandle, (void**) &newEnv, NULL); + } else { + envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL); + } + if( JNI_OK != envRes ) { fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); return NULL; } diff --git a/src/nativewindow/native/NativewindowCommon.h b/src/nativewindow/native/NativewindowCommon.h index 73b890c4f..a2975f3fd 100644 --- a/src/nativewindow/native/NativewindowCommon.h +++ b/src/nativewindow/native/NativewindowCommon.h @@ -13,6 +13,6 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...); void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached); +JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int asDaemon, int * shallBeDetached); #endif diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 81dcfa959..5d292d76e 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -689,7 +689,7 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns - (void) jRun { int shallBeDetached = 0; - JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, 1 /* asDaemon */, &shallBeDetached); DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env)); if(NULL!=env) { DBG_PRINT2("MainRunnable.1.0\n"); @@ -699,7 +699,8 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns if (shallBeDetached) { DBG_PRINT2("MainRunnable.1.3\n"); - (*jvmHandle)->DetachCurrentThread(jvmHandle); + // Keep attached on main thread ! + // (*jvmHandle)->DetachCurrentThread(jvmHandle); } } DBG_PRINT2("MainRunnable.X\n"); @@ -733,21 +734,12 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns @end - -/* - * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 - * Signature: (ZLjava/lang/Runnable;)V - */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 - (JNIEnv *env, jclass unused, jobject runnable) +static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayInMS) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - DBG_PRINT2( "RunOnMainThread0: isMainThread %d, NSApp %d, NSApp-isRunning %d\n", - (int)([NSThread isMainThread]), (int)(NULL!=NSApp), (int)([NSApp isRunning])); + DBG_PRINT2( "RunOnThread0: isMainThread %d, NSApp %d, NSApp-isRunning %d, onMain %d, delay %dms\n", + (int)([NSThread isMainThread]), (int)(NULL!=NSApp), (int)([NSApp isRunning]), (int)onMain, (int)delayInMS); - if ( NO == [NSThread isMainThread] ) { + if ( !onMain || NO == [NSThread isMainThread] ) { jobject runnableObj = (*env)->NewGlobalRef(env, runnable); JavaVM *jvmHandle = NULL; @@ -759,27 +751,56 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 jvmVersion = (*env)->GetVersion(env); } - DBG_PRINT2( "RunOnMainThread0.1.0\n"); + DBG_PRINT2( "RunOnThread.1.0\n"); MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj jvmHandle: jvmHandle jvmVersion: jvmVersion]; - [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; - DBG_PRINT2( "RunOnMainThread0.1.1\n"); + if( onMain ) { + [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; + } else { + NSTimeInterval delay = (double)delayInMS/1000.0; + [mr performSelector:@selector(jRun) withObject:nil afterDelay:delay]; + } + DBG_PRINT2( "RunOnThread.1.1\n"); [mr release]; - DBG_PRINT2( "RunOnMainThread0.1.2\n"); + DBG_PRINT2( "RunOnThread.1.2\n"); } else { - DBG_PRINT2( "RunOnMainThread0.2\n"); + DBG_PRINT2( "RunOnThread.2\n"); (*env)->CallVoidMethod(env, runnable, runnableRunID); } - DBG_PRINT2( "RunOnMainThread0.X\n"); + DBG_PRINT2( "RunOnThread.X\n"); +} +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: RunOnMainThread0 + * Signature: (ZLjava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 + (JNIEnv *env, jclass unused, jobject runnable) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, YES, 0); [pool release]; } /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 + * Method: RunLater0 + * Signature: (ZLjava/lang/Runnable;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunLater0 + (JNIEnv *env, jclass unused, jobject runnable, jint delay) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, NO, delay); + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: IsMainThread0 * Signature: (V)V */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 017c52df2..77e6ea978 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -197,7 +197,7 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) fflush(stderr); if( NULL != jvmHandle && ( errorHandlerDebug || errorHandlerThrowException ) ) { - jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, 0 /* asDaemon */, &shallBeDetached); if(NULL == jniEnv) { fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); fflush(stderr); @@ -262,7 +262,7 @@ static int x11IOErrorHandler(Display *dpy) fflush(stderr); if( NULL != jvmHandle ) { - jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, 0 /* asDaemon */, &shallBeDetached); if (NULL != jniEnv) { NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr); if (shallBeDetached) { -- cgit v1.2.3 From 8b70108d6fd04b2ab97cbd1b6729361b5ce98a6b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 24 Apr 2013 18:48:14 +0200 Subject: X11 Error Handler: Start quiet; Init: quite = !debug; Internal calls: Pass through errorHandlerQuiet state. --- src/nativewindow/native/x11/Xmisc.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 77e6ea978..69f0c0746 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -174,7 +174,7 @@ static void setupJVMVars(JNIEnv * env) { } static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerQuiet = 0 ; +static int errorHandlerQuiet = 1 ; static int errorHandlerDebug = 0 ; static int errorHandlerThrowException = 0; @@ -300,7 +300,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 1, 0, 0 /* no dpy, force, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 1, debug ? 0 : 1, 0 /* no dpy, force, no sync */); _initialized=1; if(JNI_TRUE == debug) { fprintf(stderr, "Info: NativeWindow native init passed\n"); @@ -311,7 +311,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0, 0 /* no dpy, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0 /* no dpy, no sync */); x11IOErrorHandlerEnable(0, env); } @@ -342,9 +342,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja if (arg3 != NULL) { _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, errorHandlerQuiet, 0); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, errorHandlerQuiet, 0); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -371,7 +371,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u return; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 1); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 1); memset(&xwa, 0, sizeof(XWindowAttributes)); XGetWindowAttributes(dpy, w, &xwa); if(NULL != xwa.visual) { @@ -379,7 +379,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u } else { r = 0; } - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); return r; } @@ -391,9 +391,9 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 1, errorHandlerQuiet, 0); r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, errorHandlerQuiet, 0); return r; } @@ -434,9 +434,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 1, errorHandlerQuiet, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0); return _res; } @@ -519,7 +519,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow return 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); if(0==windowParent) { @@ -542,7 +542,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow if (visual==NULL) { - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -606,7 +606,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow XSelectInput(dpy, window, 0); // no events } - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -630,12 +630,12 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow return; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); } JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize @@ -683,11 +683,11 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio if( 0 == jdest_win ) { dest_win = root; } if( 0 == jsrc_win ) { src_win = root; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); -- cgit v1.2.3 From aed9662552503b0a2fa67bcddbb7063b16d003d5 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 12 Jun 2013 11:58:55 +0200 Subject: Fix Bug 750: Leaked X11 ColorMap for each created X11 Window in NativeWindow (dummy) and NEWT Free the colormap at WindowDestroy, which we have created at WindowCreate w/ AllocNone. Due to the fact we used 'AllocNone' the leak is minimal though .. --- src/nativewindow/native/x11/Xmisc.c | 7 +++++++ src/newt/native/X11Window.c | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 69f0c0746..31620d752 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -624,6 +624,7 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow { Display * dpy = (Display *)(intptr_t)display; Window w = (Window) window; + XWindowAttributes xwa; if(NULL==dpy) { NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); @@ -631,10 +632,16 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow } NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); + XSync(dpy, False); + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, w, &xwa); // prefetch colormap to be destroyed after window destruction XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); + if( None != xwa.colormap ) { + XFreeColormap(dpy, xwa.colormap); + } // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); } diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 6c5a127b6..e567781cf 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -676,6 +676,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 Display * dpy = (Display *) (intptr_t) display; Window w = (Window)window; jobject jwindow; + XWindowAttributes xwa; if(dpy==NULL) { NewtCommon_FatalError(env, "invalid display connection.."); @@ -694,13 +695,19 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 } XSync(dpy, False); + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, w, &xwa); // prefetch colormap to be destroyed after window destruction XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); + XSync(dpy, False); // Drain all events related to this window .. Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now XDestroyWindow(dpy, w); + if( None != xwa.colormap ) { + XFreeColormap(dpy, xwa.colormap); + } XSync(dpy, True); // discard all events now, no more handler (*env)->DeleteGlobalRef(env, jwindow); -- cgit v1.2.3 From 613e33ee8ffc1f2b9c5db1e1b5bb5253a159ed6d Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Mon, 4 Nov 2013 15:07:14 +0100 Subject: Bug 888 - Validate CPU Runtime Performance: X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(..) X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(..) ran over all FB configs and for each it grabbed native config values separately. Fetching them in bulk mode saves around 7% of this function's cost. Also reuse XRenderPictFormat instance for 'XRenderDirectFormat XRenderFindVisualFormat(..)' call, saving a few NIO creation cycles w/ StructAccessor. Biggest savior is X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationFBConfig()'s fast path w/o chooser and usable 1st FBConfig. Here we only issue 'GLXFBConfig2GLCapabilities(..)' on the first valid entry. Test w/ 50 X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationFBConfig() invocations: - pre change: 1.708 ms - post change: 650 ms Time is no spent almost solely on native glXChooseFBConfig (546ms). --- make/config/jogl/glx-CustomCCode.c | 25 ++++ make/config/jogl/glx-CustomJavaCode.java | 22 ++++ make/config/nativewindow/x11-CustomJavaCode.java | 15 +++ .../x11/glx/X11GLXGraphicsConfiguration.java | 144 +++++++++++++++------ .../glx/X11GLXGraphicsConfigurationFactory.java | 46 ++++--- src/nativewindow/native/x11/Xmisc.c | 15 +++ 6 files changed, 206 insertions(+), 61 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/make/config/jogl/glx-CustomCCode.c b/make/config/jogl/glx-CustomCCode.c index 71dc68b08..5c73dfea6 100644 --- a/make/config/jogl/glx-CustomCCode.c +++ b/make/config/jogl/glx-CustomCCode.c @@ -59,6 +59,31 @@ static void _initClazzAccess(JNIEnv *env) { } } +/* Java->C glue code: + * Java package: jogamp.opengl.x11.glx.GLX + * Java method: int glXGetFBConfigAttributes(long dpy, long config, IntBuffer attributes, IntBuffer values) + */ +JNIEXPORT jint JNICALL +Java_jogamp_opengl_x11_glx_GLX_dispatch_1glXGetFBConfigAttributes(JNIEnv *env, jclass _unused, jlong dpy, jlong config, jint attributeCount, jobject attributes, jint attributes_byte_offset, jobject values, jint values_byte_offset, jlong procAddress) { + typedef int (APIENTRY*_local_PFNGLXGETFBCONFIGATTRIBPROC)(Display * dpy, GLXFBConfig config, int attribute, int * value); + _local_PFNGLXGETFBCONFIGATTRIBPROC ptr_glXGetFBConfigAttrib = (_local_PFNGLXGETFBCONFIGATTRIBPROC) (intptr_t) procAddress; + assert(ptr_glXGetFBConfigAttrib != NULL); + + int err = 0; + if ( attributeCount > 0 && NULL != attributes ) { + int i; + int * attributes_ptr = (int *) (((char*) (*env)->GetDirectBufferAddress(env, attributes)) + attributes_byte_offset); + int * values_ptr = (int *) (((char*) (*env)->GetDirectBufferAddress(env, values)) + values_byte_offset); + for(i=0; 0 == err && iC glue code: * Java package: jogamp.opengl.x11.glx.GLX * Java method: XVisualInfo glXGetVisualFromFBConfig(long dpy, long config) diff --git a/make/config/jogl/glx-CustomJavaCode.java b/make/config/jogl/glx-CustomJavaCode.java index f3e743930..4cce05dda 100644 --- a/make/config/jogl/glx-CustomJavaCode.java +++ b/make/config/jogl/glx-CustomJavaCode.java @@ -1,4 +1,26 @@ + /** + * Returns the GLX error value, i.e. 0 for no error. In case of an error values.get(values.getPosition()) contains the attributes index causing the error. + *

+ * Entry point to C language function: int glXGetFBConfigAttrib(Display * dpy, GLXFBConfig config, int attribute, int * value);
Part of GLX_VERSION_1_3 + *

+ */ + public static int glXGetFBConfigAttributes(long dpy, long config, IntBuffer attributes, IntBuffer values) { + if( attributes == null || values == null ) { + throw new RuntimeException("arrays buffers are null"); + } + if( !Buffers.isDirect(attributes) || !Buffers.isDirect(values) ) { + throw new RuntimeException("arrays buffers are not direct"); + } + if( attributes.remaining() > values.remaining() ) { + throw new RuntimeException("not enough values "+values+" for attributes "+attributes); + } + final long __addr = glxProcAddressTable._addressof_glXGetFBConfigAttrib; + return dispatch_glXGetFBConfigAttributes(dpy, config, attributes.remaining(), attributes, Buffers.getDirectBufferByteOffset(attributes), + values, Buffers.getDirectBufferByteOffset(values), __addr); + } + private static native int dispatch_glXGetFBConfigAttributes(long dpy, long config, int attributeCount, Object attributes, int attributes_byte_offset, Object values, int valuesOffset, long procAddr); + /** Interface to C language function:
- Alias for:
XVisualInfo * glXGetVisualFromFBConfigSGIX, glXGetVisualFromFBConfig(Display * dpy, GLXFBConfig config); */ public static XVisualInfo glXGetVisualFromFBConfig(long dpy, long config) { diff --git a/make/config/nativewindow/x11-CustomJavaCode.java b/make/config/nativewindow/x11-CustomJavaCode.java index 4240c5e2f..d1e011184 100644 --- a/make/config/nativewindow/x11-CustomJavaCode.java +++ b/make/config/nativewindow/x11-CustomJavaCode.java @@ -1,4 +1,19 @@ + /** Interface to C language function:
XRenderPictFormat * XRenderFindVisualFormat(Display * dpy, const Visual * visual); */ + public static boolean XRenderFindVisualFormat(long dpy, long visual, XRenderPictFormat dest) { + if( dest == null ) { + throw new RuntimeException("dest is null"); + } + final ByteBuffer destBuffer = dest.getBuffer(); + if( !Buffers.isDirect(destBuffer) ) { + throw new RuntimeException("dest buffer is not direct"); + } + return XRenderFindVisualFormat1(dpy, visual, destBuffer); + } + /** Entry point to C language function: XVisualInfo * XGetVisualInfo(Display * , long, XVisualInfo * , int * ); */ + private static native boolean XRenderFindVisualFormat1(long dpy, long visual, ByteBuffer xRenderPictFormat); + + /** Interface to C language function:
XVisualInfo * XGetVisualInfo(Display * , long, XVisualInfo * , int * ); */ public static XVisualInfo[] XGetVisualInfo(long arg0, long arg1, XVisualInfo arg2, int[] arg3, int arg3_offset) { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java index 4d1ed3985..ee3e1a3d7 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java @@ -34,6 +34,8 @@ package jogamp.opengl.x11.glx; import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; @@ -61,7 +63,7 @@ import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implements Cloneable { public static final int MAX_ATTRIBS = 128; - private GLCapabilitiesChooser chooser; + private final GLCapabilitiesChooser chooser; X11GLXGraphicsConfiguration(X11GraphicsScreen screen, X11GLCapabilities capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser) { @@ -274,15 +276,47 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem } return renderPictFmt.getDirect(); } + static XRenderDirectFormat XVisual2XRenderMask(long dpy, long visual, XRenderPictFormat dest) { + if( !X11Lib.XRenderFindVisualFormat(dpy, visual, dest) ) { + return null; + } else { + return dest.getDirect(); + } + } + + static X11GLCapabilities GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final long fbcfg, + final int winattrmask, final boolean isMultisampleAvailable) { + final IntBuffer tmp = Buffers.newDirectIntBuffer(1); + final XRenderPictFormat xRenderPictFormat= XRenderPictFormat.create(); + return GLXFBConfig2GLCapabilities(device, glp, fbcfg, winattrmask, isMultisampleAvailable, tmp, xRenderPictFormat); + } - static X11GLCapabilities GLXFBConfig2GLCapabilities(X11GraphicsDevice device, GLProfile glp, long fbcfg, - int winattrmask, boolean isMultisampleAvailable) { + static List GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final PointerBuffer fbcfgsL, + final int winattrmask, final boolean isMultisampleAvailable, boolean onlyFirstValid) { + final IntBuffer tmp = Buffers.newDirectIntBuffer(1); + final XRenderPictFormat xRenderPictFormat= XRenderPictFormat.create(); + final List result = new ArrayList(); + for (int i = 0; i < fbcfgsL.limit(); i++) { + final long fbcfg = fbcfgsL.get(i); + final GLCapabilitiesImmutable c = GLXFBConfig2GLCapabilities(device, glp, fbcfg, winattrmask, isMultisampleAvailable, tmp, xRenderPictFormat); + if( null != c ) { + result.add(c); + if( onlyFirstValid ) { + break; + } + } + } + return result; + } + static X11GLCapabilities GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final long fbcfg, + final int winattrmask, final boolean isMultisampleAvailable, + final IntBuffer tmp, final XRenderPictFormat xRenderPictFormat) { + final long display = device.getHandle(); final int allDrawableTypeBits = FBCfgDrawableTypeBits(device, fbcfg); int drawableTypeBits = winattrmask & allDrawableTypeBits; - final long display = device.getHandle(); - int fbcfgid = X11GLXGraphicsConfiguration.glXFBConfig2FBConfigID(display, fbcfg); - XVisualInfo visualInfo = GLX.glXGetVisualFromFBConfig(display, fbcfg); + final int fbcfgid = X11GLXGraphicsConfiguration.glXFBConfig2FBConfigID(display, fbcfg); + final XVisualInfo visualInfo = GLX.glXGetVisualFromFBConfig(display, fbcfg); if(null == visualInfo) { if(DEBUG) { System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: Null XVisualInfo for FBConfigID 0x" + Integer.toHexString(fbcfgid)); @@ -290,51 +324,87 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem // onscreen must have an XVisualInfo drawableTypeBits &= ~(GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.FBO_BIT); } - if( 0 == drawableTypeBits ) { - return null; + if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: zero drawablebits: winattrmask: "+toHexString(winattrmask)+", offscreen "+(null == visualInfo)); + } + return null; } - final IntBuffer tmp = Buffers.newDirectIntBuffer(1); if(GLX.GLX_BAD_ATTRIBUTE == GLX.glXGetFBConfigAttrib(display, fbcfg, GLX.GLX_RENDER_TYPE, tmp)) { + if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: FBConfig invalid (1): fbcfg: "+toHexString(fbcfg)); + } return null; } if( 0 == ( GLX.GLX_RGBA_BIT & tmp.get(0) ) ) { - return null; // no RGBA -> color index not supported + // no RGBA -> color index not supported + if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: FBConfig not RGBA (2): fbcfg: "+toHexString(fbcfg)); + } + return null; } - final X11GLCapabilities res = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp); - if (isMultisampleAvailable) { - res.setSampleBuffers(glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLE_BUFFERS, tmp) != 0); - res.setNumSamples (glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLES, tmp)); - } + final X11GLCapabilities caps = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp); + final XRenderDirectFormat xrmask = ( null != visualInfo ) ? - XVisual2XRenderMask( display, visualInfo.getVisual() ) : + XVisual2XRenderMask( display, visualInfo.getVisual(), xRenderPictFormat) : null ; + + final int _attributes[] = { + GLX.GLX_SAMPLE_BUFFERS, + GLX.GLX_SAMPLES, + GLX.GLX_DOUBLEBUFFER, + GLX.GLX_STEREO, + GLX.GLX_CONFIG_CAVEAT, + GLX.GLX_RED_SIZE, + GLX.GLX_GREEN_SIZE, + GLX.GLX_BLUE_SIZE, + GLX.GLX_ALPHA_SIZE, + GLX.GLX_ACCUM_RED_SIZE, + GLX.GLX_ACCUM_GREEN_SIZE, + GLX.GLX_ACCUM_BLUE_SIZE, + GLX.GLX_ACCUM_ALPHA_SIZE, + GLX.GLX_DEPTH_SIZE, + GLX.GLX_STENCIL_SIZE + }; + final int offset = isMultisampleAvailable ? 0 : 2; + final IntBuffer attributes = Buffers.newDirectIntBuffer(_attributes); + attributes.position(offset); + final IntBuffer values = Buffers.newDirectIntBuffer(attributes.remaining()); + final int err = GLX.glXGetFBConfigAttributes(display, fbcfg, attributes, values); + if (0 != err) { + throw new GLException("glXGetFBConfig("+toHexString(attributes.get(offset+values.get(0)))+") failed: error code " + glXGetFBConfigErrorCode(err)); + } + int j=0; + if (isMultisampleAvailable) { + caps.setSampleBuffers(values.get(j++) != 0); + caps.setNumSamples (values.get(j++)); + } final int alphaMask = ( null != xrmask ) ? xrmask.getAlphaMask() : 0; - res.setBackgroundOpaque( 0 >= alphaMask ); - if( !res.isBackgroundOpaque() ) { - res.setTransparentRedValue(xrmask.getRedMask()); - res.setTransparentGreenValue(xrmask.getGreenMask()); - res.setTransparentBlueValue(xrmask.getBlueMask()); - res.setTransparentAlphaValue(alphaMask); + caps.setBackgroundOpaque( 0 >= alphaMask ); + if( !caps.isBackgroundOpaque() ) { + caps.setTransparentRedValue(xrmask.getRedMask()); + caps.setTransparentGreenValue(xrmask.getGreenMask()); + caps.setTransparentBlueValue(xrmask.getBlueMask()); + caps.setTransparentAlphaValue(alphaMask); } // ALPHA shall be set at last - due to it's auto setting by the above (!opaque / samples) - res.setDoubleBuffered(glXGetFBConfig(display, fbcfg, GLX.GLX_DOUBLEBUFFER, tmp) != 0); - res.setStereo (glXGetFBConfig(display, fbcfg, GLX.GLX_STEREO, tmp) != 0); - res.setHardwareAccelerated(glXGetFBConfig(display, fbcfg, GLX.GLX_CONFIG_CAVEAT, tmp) != GLX.GLX_SLOW_CONFIG); - res.setRedBits (glXGetFBConfig(display, fbcfg, GLX.GLX_RED_SIZE, tmp)); - res.setGreenBits (glXGetFBConfig(display, fbcfg, GLX.GLX_GREEN_SIZE, tmp)); - res.setBlueBits (glXGetFBConfig(display, fbcfg, GLX.GLX_BLUE_SIZE, tmp)); - res.setAlphaBits (glXGetFBConfig(display, fbcfg, GLX.GLX_ALPHA_SIZE, tmp)); - res.setAccumRedBits (glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_RED_SIZE, tmp)); - res.setAccumGreenBits(glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_GREEN_SIZE, tmp)); - res.setAccumBlueBits (glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_BLUE_SIZE, tmp)); - res.setAccumAlphaBits(glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_ALPHA_SIZE, tmp)); - res.setDepthBits (glXGetFBConfig(display, fbcfg, GLX.GLX_DEPTH_SIZE, tmp)); - res.setStencilBits (glXGetFBConfig(display, fbcfg, GLX.GLX_STENCIL_SIZE, tmp)); - - return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res); + caps.setDoubleBuffered(values.get(j++) != 0); + caps.setStereo (values.get(j++) != 0); + caps.setHardwareAccelerated(values.get(j++) != GLX.GLX_SLOW_CONFIG); + caps.setRedBits (values.get(j++)); + caps.setGreenBits (values.get(j++)); + caps.setBlueBits (values.get(j++)); + caps.setAlphaBits (values.get(j++)); + caps.setAccumRedBits (values.get(j++)); + caps.setAccumGreenBits(values.get(j++)); + caps.setAccumBlueBits (values.get(j++)); + caps.setAccumAlphaBits(values.get(j++)); + caps.setDepthBits (values.get(j++)); + caps.setStencilBits (values.get(j++)); + + return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, caps); } private static String glXGetFBConfigErrorCode(int err) { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java index 6050dabbb..5c84597d5 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java @@ -287,24 +287,23 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF final IntBuffer attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, true, isMultisampleAvailable, display, screen); final IntBuffer count = Buffers.newDirectIntBuffer(1); count.put(0, -1); - List availableCaps = new ArrayList(); final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen); + List availableCaps; // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice, // skipped if xvisualID is given + final boolean hasGLXChosenCaps; if( VisualIDHolder.VID_UNDEFINED == xvisualID ) { fbcfgsL = GLX.glXChooseFBConfig(display, screen, attribs, count); + hasGLXChosenCaps = fbcfgsL != null && fbcfgsL.limit()>0; + } else { + hasGLXChosenCaps = false; } - if (fbcfgsL != null && fbcfgsL.limit()>0) { - for (int i = 0; i < fbcfgsL.limit(); i++) { - final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL.get(i), winattrmask, isMultisampleAvailable); - if( null != caps ) { - availableCaps.add(caps); - } else if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (1): ("+x11Screen+","+capsChosen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); - } - } + final boolean useRecommendedIndex = hasGLXChosenCaps && capsChosen.isBackgroundOpaque(); // only use recommended idx if not translucent + final boolean skipCapsChooser = null == chooser && useRecommendedIndex; // fast path: skip choosing if using recommended idx and null chooser is used + if (hasGLXChosenCaps) { + availableCaps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL, winattrmask, isMultisampleAvailable, skipCapsChooser /* onlyFirstValid */); if(availableCaps.size() > 0) { - recommendedIndex = capsChosen.isBackgroundOpaque() ? 0 : -1; // only use recommended idx if not translucent + recommendedIndex = useRecommendedIndex ? 0 : -1; if (DEBUG) { System.err.println("glXChooseFBConfig recommended fbcfg " + toHexString(fbcfgsL.get(0)) + ", idx " + recommendedIndex); System.err.println("user caps " + capsChosen); @@ -314,6 +313,8 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF System.err.println("glXChooseFBConfig no caps for recommended fbcfg " + toHexString(fbcfgsL.get(0))); System.err.println("user caps " + capsChosen); } + } else { + availableCaps = new ArrayList(); } // 2nd choice: get all GLCapabilities available, no preferred recommendedIndex available @@ -328,15 +329,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } return null; } - - for (int i = 0; i < fbcfgsL.limit(); i++) { - final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL.get(i), winattrmask, isMultisampleAvailable); - if( null != caps ) { - availableCaps.add(caps); - } else if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); - } - } + availableCaps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL, winattrmask, isMultisampleAvailable, false /* onlyOneValid */); } if(DEBUG) { @@ -346,9 +339,9 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } } - if( VisualIDHolder.VID_UNDEFINED != xvisualID ) { + if( VisualIDHolder.VID_UNDEFINED != xvisualID ) { // implies !hasGLXChosenCaps for(int i=0; i chosenIndex ) { if (DEBUG) { System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: failed, return null"); @@ -445,7 +443,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF if( VisualIDHolder.VID_UNDEFINED != xvisualID ) { for(int i=0; i +#include + // #define VERBOSE_ON 1 #ifdef VERBOSE_ON @@ -320,6 +322,19 @@ Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _un NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, force, no sync */); } +/* Java->C glue code: + * Java package: jogamp.nativewindow.x11.X11Lib + * Java method: boolean XRenderFindVisualFormat(long dpy, long visual, XRenderPictFormat dest) + */ +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_x11_X11Lib_XRenderFindVisualFormat1(JNIEnv *env, jclass _unused, jlong dpy, jlong visual, jobject xRenderPictFormat) { + XRenderPictFormat * dest = (XRenderPictFormat *) (*env)->GetDirectBufferAddress(env, xRenderPictFormat); + XRenderPictFormat * src = XRenderFindVisualFormat((Display *) (intptr_t) dpy, (Visual *) (intptr_t) visual); + if (NULL == src) return JNI_FALSE; + memcpy(dest, src, sizeof(XRenderPictFormat)); + return JNI_TRUE; +} + /* Java->C glue code: * Java package: jogamp.nativewindow.x11.X11Lib * Java method: XVisualInfo XGetVisualInfo(long arg0, long arg1, XVisualInfo arg2, java.nio.IntBuffer arg3) -- cgit v1.2.3 From 1d426dd08797a3164e0a7cdf6007d3e750650265 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 5 Nov 2013 16:53:18 +0100 Subject: JNI Code: Call DeleteLocalRef(..) manually. --- src/jogl/native/libav/ffmpeg_impl_template.c | 1 + src/nativewindow/native/x11/Xmisc.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src/nativewindow/native/x11') diff --git a/src/jogl/native/libav/ffmpeg_impl_template.c b/src/jogl/native/libav/ffmpeg_impl_template.c index 34a2baeb7..24fddd2c0 100644 --- a/src/jogl/native/libav/ffmpeg_impl_template.c +++ b/src/jogl/native/libav/ffmpeg_impl_template.c @@ -1275,6 +1275,7 @@ JNIEXPORT jint JNICALL FF_FUNC(readNextPacket0) pNIOBufferCurrent->nioRef = (*env)->NewGlobalRef(env, jSampleData); pNIOBufferCurrent->origPtr = data_ptr; pNIOBufferCurrent->size = data_size; + (*env)->DeleteLocalRef(env, jSampleData); if(pAV->verbose) { fprintf(stderr, "A NIO: Alloc ptr %p / ref %p, %d bytes\n", pNIOBufferCurrent->origPtr, pNIOBufferCurrent->nioRef, pNIOBufferCurrent->size); diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 2bf740233..442d0ceef 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -368,6 +368,7 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja jbyteSource = (*env)->NewDirectByteBuffer(env, _res, count * sizeof(XVisualInfo)); jbyteCopy = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffers, jbyteSource); + (*env)->DeleteLocalRef(env, jbyteSource); XFree(_res); -- cgit v1.2.3 From c153a453299ef12bdb635dc11574a21bba74f04c Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 17 Nov 2013 05:31:22 +0100 Subject: Fix GLIBC > 2.4 dependency regression of commit 613e33ee8ffc1f2b9c5db1e1b5bb5253a159ed6d Commit 613e33ee8ffc1f2b9c5db1e1b5bb5253a159ed6d introduced 'memcpy' usage in Xmisc.c which could create a GLIBC > 2.4 dependency. Include GlueGen's glibc-compat-symbols.h to remove such dependency. --- src/nativewindow/native/x11/Xmisc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 442d0ceef..2c0e4e22b 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -35,6 +35,9 @@ #include +/** Remove memcpy GLIBC > 2.4 dependencies */ +#include + // #define VERBOSE_ON 1 #ifdef VERBOSE_ON -- cgit v1.2.3 From 380528f59c4a37429f4fa5f8ac7aa3076d0eaa11 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 17 Nov 2013 17:28:10 +0100 Subject: Nativewindow/NEWT: Fix C Return Statement --- src/nativewindow/native/x11/Xmisc.c | 2 +- src/newt/native/X11RandR11.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 2c0e4e22b..7b9dc344b 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -387,7 +387,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u if(NULL==dpy) { NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); - return; + return 0; } NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 1); diff --git a/src/newt/native/X11RandR11.c b/src/newt/native/X11RandR11.c index 53d01a6fe..38d61289b 100644 --- a/src/newt/native/X11RandR11.c +++ b/src/newt/native/X11RandR11.c @@ -335,7 +335,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_setCurrentScreenM int rot; do { if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { - return; + return JNI_FALSE; // not done } XNextEvent(dpy, &evt); @@ -366,5 +366,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_setCurrentScreenM XSync(dpy, False); + return done ? JNI_TRUE : JNI_FALSE; } -- cgit v1.2.3 From 5ef83c2b8576ccd764ffc4953eea506bd96277c3 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 11 Jan 2014 00:04:18 +0100 Subject: X11: Harden usage of 'XGetWindowProperty(..)' and 'XGetVisualInfo' - Add missing XFree(..) calls and argument checks. --- src/nativewindow/native/x11/Xmisc.c | 36 ++++++++++---------- src/newt/native/X11Window.c | 66 +++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 47 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 7b9dc344b..5e6909f6e 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -219,7 +219,6 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); } - if (shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } @@ -347,25 +346,24 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(JNIEnv *env, jclass _unused, jlong arg0, jlong arg1, jobject arg2, jobject arg3, jint arg3_byte_offset) { XVisualInfo * _ptr2 = NULL; int * _ptr3 = NULL; - XVisualInfo * _res; - int count; - jobject jbyteSource; - jobject jbyteCopy; - if(0==arg0) { - NativewindowCommon_FatalError(env, "invalid display connection.."); - } - if (arg2 != NULL) { - _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0); - } - if (arg3 != NULL) { - _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); + XVisualInfo * _res = NULL; + int count = 0; + jobject jbyteSource = NULL; + jobject jbyteCopy = NULL; + if( 0 == arg0 || 0 == arg2 || 0 == arg3 ) { + NativewindowCommon_FatalError(env, "invalid display connection, vinfo_template or nitems_return"); + return NULL; } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, errorHandlerQuiet, 0); - _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, errorHandlerQuiet, 0); - count = _ptr3[0]; - if (arg3 != NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); + _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0); + if( NULL != _ptr2 ) { + _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); + if( NULL != _ptr3 ) { + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, errorHandlerQuiet, 0); + _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, errorHandlerQuiet, 0); + count = _ptr3[0]; + (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); + } } if (_res == NULL) return NULL; diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 54b85c243..2cc66c78d 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -98,11 +98,11 @@ static void setJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlon } jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning) { - Atom actual_type; - int actual_format; + Atom actual_type = 0; + int actual_format = 0; int nitems_32 = ( sizeof(uintptr_t) == 8 ) ? 2 : 1 ; unsigned char * jogl_java_object_data_pp = NULL; - jobject jwindow; + jobject jwindow = 0; { unsigned long nitems= 0; @@ -122,7 +122,9 @@ jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong ja } if(actual_type!=(Atom)javaObjectAtom || nitems= PROP_MWM_HINTS_ELEMENTS) { // unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status unsigned long *hints = (unsigned long *) wm_data; decor = ( 0 != (hints[0] & MWM_HINTS_DECORATIONS) ) && ( 0 != hints[2] ); } + if( NULL != wm_data ) { + XFree(wm_data); + } } #endif @@ -319,27 +326,30 @@ static int NewtWindows_getSupportedStackingEWMHFlags(Display *dpy, Window w) { Atom _NET_WM_ALLOWED_ACTIONS = XInternAtom( dpy, "_NET_WM_ALLOWED_ACTIONS", False ); Atom _NET_WM_ACTION_FULLSCREEN = XInternAtom( dpy, "_NET_WM_ACTION_FULLSCREEN", False ); Atom _NET_WM_ACTION_ABOVE = XInternAtom( dpy, "_NET_WM_ACTION_ABOVE", False ); - Atom * actions; - Atom type; - unsigned long action_len, remain; - int res = 0, form, i; + Atom * actions = NULL; + Atom type = 0; + unsigned long action_len = 0, remain = 0; + int res = 0, form = 0, i = 0; Status s; if ( Success == (s = XGetWindowProperty(dpy, w, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, AnyPropertyType, &type, &form, &action_len, &remain, (unsigned char**)&actions)) ) { - for(i=0; i Date: Sat, 11 Jan 2014 02:11:47 +0100 Subject: [Jogl|Nativewindow|Newt]Common: Align all *Common_GetJNIEnv()/_ReleaseJNIEnv() Methods and Usage / Check arguments .. Since we still don't use inter-module native code sharing, align the JNIEnv get/release methods and usage. Most beneficary here is OSX and the GLDebugMessageHandle, both managed the JVM handle on their own - removed now. Also ensuring that *Common_init(..) is called for all modules on all platforms. --- src/jogl/native/GLContext.c | 2 +- src/jogl/native/GLDebugMessageHandler.c | 95 ++++--------- src/jogl/native/JoglCommon.c | 97 ++++++------- src/jogl/native/JoglCommon.h | 55 ++++++-- src/jogl/native/libav/ffmpeg_impl_template.c | 4 +- .../macosx/MacOSXWindowSystemInterface-calayer.m | 1 + .../jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c | 5 +- src/nativewindow/native/NativewindowCommon.c | 110 ++++++++++----- src/nativewindow/native/NativewindowCommon.h | 61 ++++++++- src/nativewindow/native/macosx/OSXmisc.m | 34 ++--- src/nativewindow/native/win32/GDImisc.c | 2 +- src/nativewindow/native/x11/Xmisc.c | 126 +++++++---------- src/newt/native/MacWindow.m | 13 +- src/newt/native/NewtCommon.c | 96 +++++++++---- src/newt/native/NewtCommon.h | 26 ++-- src/newt/native/NewtMacWindow.h | 10 -- src/newt/native/NewtMacWindow.m | 152 ++++++--------------- 17 files changed, 431 insertions(+), 458 deletions(-) (limited to 'src/nativewindow/native/x11') diff --git a/src/jogl/native/GLContext.c b/src/jogl/native/GLContext.c index f10d0e421..9be9f82af 100644 --- a/src/jogl/native/GLContext.c +++ b/src/jogl/native/GLContext.c @@ -19,7 +19,7 @@ Java_jogamp_opengl_GLContextImpl_glGetStringInt(JNIEnv *env, jclass _unused, jin assert(ptr_glGetString != NULL); _res = (* ptr_glGetString) ((unsigned int) name); if (NULL == _res) return NULL; - return (*env)->NewStringUTF(env, _res); + return (*env)->NewStringUTF(env, (const char *)_res); } /* diff --git a/src/jogl/native/GLDebugMessageHandler.c b/src/jogl/native/GLDebugMessageHandler.c index 2e9d6033a..0aa7a01e7 100644 --- a/src/jogl/native/GLDebugMessageHandler.c +++ b/src/jogl/native/GLDebugMessageHandler.c @@ -49,8 +49,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_opengl_GLDebugMessageHandler_initIDs0 } typedef struct { - JavaVM *vm; - int version; jobject obj; int extType; } DebugHandlerType; @@ -60,39 +58,21 @@ typedef struct { static void GLDebugMessageARBCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam) { DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) userParam; - JavaVM *vm = handle->vm; - int version = handle->version; jobject obj = handle->obj; - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; - DBG_PRINT("GLDebugMessageARBCallback: 00 - %s, vm %p, version 0x%X, jobject %p, extType %d\n", - message, handle->vm, handle->version, (void*)handle->obj, handle->extType); - - // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*vm)->GetEnv(vm, (void **) &curEnv, version) ; - DBG_PRINT("GLDebugMessageARBCallback: 01 - JVM Env: curEnv %p, res 0x%X\n", curEnv, envRes); - if( JNI_EDETACHED == envRes ) { - // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*vm)->AttachCurrentThread(vm, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "GLDebugMessageARBCallback: can't attach thread: %d\n", envRes); - return; - } - curEnv = newEnv; - DBG_PRINT("GLDebugMessageARBCallback: 02 - attached .. \n"); - } else if( JNI_OK != envRes ) { - // oops .. - fprintf(stderr, "GLDebugMessageARBCallback: can't GetEnv: %d\n", envRes); + JNIEnv *env = NULL; + int shallBeDetached ; + DBG_PRINT("GLDebugMessageARBCallback: 00 - %s, jobject %p, extType %d\n", message, (void*)handle->obj, handle->extType); + + env = JoglCommon_GetJNIEnv (1 /* asDaemon */, &shallBeDetached); + if( NULL == env ) { + DBG_PRINT("GLDebugMessageARBCallback: Null JNIEnv\n"); return; } - (*curEnv)->CallVoidMethod(curEnv, obj, glDebugMessageARB, + (*env)->CallVoidMethod(env, obj, glDebugMessageARB, (jint) source, (jint) type, (jint) id, (jint) severity, - (*curEnv)->NewStringUTF(curEnv, message)); - if( NULL != newEnv ) { - // detached attached thread - (*vm)->DetachCurrentThread(vm); - DBG_PRINT("GLDebugMessageARBCallback: 04 - detached .. \n"); - } + (*env)->NewStringUTF(env, message)); + // detaching thread not required - daemon + // JoglCommon_ReleaseJNIEnv(shallBeDetached); DBG_PRINT("GLDebugMessageARBCallback: 0X\n"); /** * On Java 32bit on 64bit Windows and w/ GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB disables, @@ -104,39 +84,21 @@ static void GLDebugMessageARBCallback(GLenum source, GLenum type, GLuint id, GLe static void GLDebugMessageAMDCallback(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam) { DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) userParam; - JavaVM *vm = handle->vm; - int version = handle->version; jobject obj = handle->obj; - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; - DBG_PRINT("GLDebugMessageAMDCallback: 00 - %s, vm %p, version 0x%X, jobject %p, extType %d\n", - message, handle->vm, handle->version, (void*)handle->obj, handle->extType); - - // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*vm)->GetEnv(vm, (void **) &curEnv, version) ; - DBG_PRINT("GLDebugMessageAMDCallback: 01 - JVM Env: curEnv %p, res 0x%X\n", curEnv, envRes); - if( JNI_EDETACHED == envRes ) { - // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*vm)->AttachCurrentThread(vm, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "GLDebugMessageAMDCallback: can't attach thread: %d\n", envRes); - return; - } - curEnv = newEnv; - DBG_PRINT("GLDebugMessageAMDCallback: 02 - attached .. \n"); - } else if( JNI_OK != envRes ) { - // oops .. - fprintf(stderr, "GLDebugMessageAMDCallback: can't GetEnv: %d\n", envRes); + JNIEnv *env = NULL; + int shallBeDetached ; + DBG_PRINT("GLDebugMessageAMDCallback: 00 - %s, jobject %p, extType %d\n", message, (void*)handle->obj, handle->extType); + + env = JoglCommon_GetJNIEnv (1 /* asDaemon */, &shallBeDetached); + if( NULL == env ) { + DBG_PRINT("GLDebugMessageARBCallback: Null JNIEnv\n"); return; } - (*curEnv)->CallVoidMethod(curEnv, obj, glDebugMessageAMD, + (*env)->CallVoidMethod(env, obj, glDebugMessageAMD, (jint) id, (jint) category, (jint) severity, - (*curEnv)->NewStringUTF(curEnv, message)); - if( NULL != newEnv ) { - // detached attached thread - (*vm)->DetachCurrentThread(vm); - DBG_PRINT("GLDebugMessageAMDCallback: 04 - detached .. \n"); - } + (*env)->NewStringUTF(env, message)); + // detached attached thread not required - daemon + // JoglCommon_ReleaseJNIEnv(shallBeDetached); DBG_PRINT("GLDebugMessageAMDCallback: 0X\n"); /** * On Java 32bit on 64bit Windows, @@ -153,18 +115,10 @@ static void GLDebugMessageAMDCallback(GLuint id, GLenum category, GLenum severit JNIEXPORT jlong JNICALL Java_jogamp_opengl_GLDebugMessageHandler_register0 (JNIEnv *env, jobject obj, jlong procAddress, jint extType) { - JavaVM *vm; DebugHandlerType * handle = malloc(sizeof(DebugHandlerType)); - if(0 != (*env)->GetJavaVM(env, &vm)) { - vm = NULL; - JoglCommon_throwNewRuntimeException(env, "GetJavaVM failed"); - } - handle->vm = vm; - handle->version = (*env)->GetVersion(env); handle->obj = (*env)->NewGlobalRef(env, obj); handle->extType = extType; - DBG_PRINT("GLDebugMessageHandler.register0: vm %p, version 0x%X, jobject %p, extType %d\n", - handle->vm, handle->version, (void*)handle->obj, handle->extType); + DBG_PRINT("GLDebugMessageHandler.register0: jobject %p, extType %d\n", (void*)handle->obj, handle->extType); if(jogamp_opengl_GLDebugMessageHandler_EXT_ARB == extType) { _local_PFNGLDEBUGMESSAGECALLBACKARBPROC ptr_glDebugMessageCallbackARB; @@ -191,8 +145,7 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_GLDebugMessageHandler_unregister0 { DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) jhandle; - DBG_PRINT("GLDebugMessageHandler.unregister0: vm %p, version 0x%X, jobject %p, extType %d\n", - handle->vm, handle->version, (void*)handle->obj, handle->extType); + DBG_PRINT("GLDebugMessageHandler.unregister0: jobject %p, extType %d\n", (void*)handle->obj, handle->extType); if(JNI_FALSE == (*env)->IsSameObject(env, obj, handle->obj)) { JoglCommon_throwNewRuntimeException(env, "wrong handle (obj doesn't match)"); diff --git a/src/jogl/native/JoglCommon.c b/src/jogl/native/JoglCommon.c index 4170b13ec..e9984ada2 100644 --- a/src/jogl/native/JoglCommon.c +++ b/src/jogl/native/JoglCommon.c @@ -11,42 +11,38 @@ static JavaVM *_jvmHandle = NULL; static int _jvmVersion = 0; void JoglCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { + if(NULL==_jvmHandle) { + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + JoglCommon_FatalError(env, "JOGL: Can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); if(NULL==c) { - JoglCommon_FatalError(env, "JOGL: can't find %s", ClazzNameRuntimeException); + JoglCommon_FatalError(env, "JOGL: Can't find %s", ClazzNameRuntimeException); } runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); (*env)->DeleteLocalRef(env, c); if(NULL==runtimeExceptionClz) { - JoglCommon_FatalError(env, "JOGL: can't use %s", ClazzNameRuntimeException); + JoglCommon_FatalError(env, "JOGL: Can't use %s", ClazzNameRuntimeException); } } - if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { - JoglCommon_FatalError(env, "JOGL: can't fetch JavaVM handle"); - } else { - _jvmVersion = (*env)->GetVersion(env); - } } void JoglCommon_FatalError(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; - int shallBeDetached = 0; - - if(NULL == env) { - env = JoglCommon_GetJNIEnv (&shallBeDetached); - } - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); - fprintf(stderr, "%s\n", buffer); - if(NULL != env) { - (*env)->FatalError(env, buffer); - JoglCommon_ReleaseJNIEnv (shallBeDetached); + fprintf(stderr, "%s\n", buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + } } } @@ -54,48 +50,42 @@ void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; - int shallBeDetached = 0; - if(NULL == env) { - env = JoglCommon_GetJNIEnv (&shallBeDetached); + if(NULL==_jvmHandle) { + JoglCommon_FatalError(env, "JOGL: NULL JVM handle, call JoglCommon_init 1st\n"); + return; } - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); - if(NULL != env) { - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); - JoglCommon_ReleaseJNIEnv (shallBeDetached); + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); + } } } -JavaVM *JoglCommon_GetJVMHandle() { - return _jvmHandle; -} - -int JoglCommon_GetJVMVersion() { - return _jvmVersion; -} - jchar* JoglCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; - strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); - if (strChars != NULL) { - (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + if( NULL != env && 0 != str ) { + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } } return strChars; } -JNIEnv* JoglCommon_GetJNIEnv (int * shallBeDetached) -{ +JNIEnv* JoglCommon_GetJNIEnv (int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; - if(NULL == _jvmHandle) { - fprintf(stderr, "JOGL: No JavaVM handle registered, call JoglCommon_init(..) 1st"); + if(NULL==_jvmHandle) { + fprintf(stderr, "JOGL GetJNIEnv: NULL JVM handle, call JoglCommon_init 1st\n"); return NULL; } @@ -103,18 +93,23 @@ JNIEnv* JoglCommon_GetJNIEnv (int * shallBeDetached) envRes = (*_jvmHandle)->GetEnv(_jvmHandle, (void **) &curEnv, _jvmVersion) ; if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); + if( asDaemon ) { + envRes = (*_jvmHandle)->AttachCurrentThreadAsDaemon(_jvmHandle, (void**) &newEnv, NULL); + } else { + envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL); + } + if( JNI_OK != envRes ) { + fprintf(stderr, "JOGL GetJNIEnv: Can't attach thread: %d\n", envRes); return NULL; } curEnv = newEnv; } else if( JNI_OK != envRes ) { // oops .. - fprintf(stderr, "can't GetEnv: %d\n", envRes); + fprintf(stderr, "JOGL GetJNIEnv: Can't GetEnv: %d\n", envRes); return NULL; } if (curEnv==NULL) { - fprintf(stderr, "env is NULL\n"); + fprintf(stderr, "JOGL GetJNIEnv: env is NULL\n"); return NULL; } *shallBeDetached = NULL != newEnv; @@ -123,10 +118,8 @@ JNIEnv* JoglCommon_GetJNIEnv (int * shallBeDetached) void JoglCommon_ReleaseJNIEnv (int shallBeDetached) { if(NULL == _jvmHandle) { - fprintf(stderr, "JOGL: No JavaVM handle registered, call JoglCommon_init(..) 1st"); - } - - if(shallBeDetached) { + fprintf(stderr, "JOGL ReleaseJNIEnv: No JavaVM handle registered, call JoglCommon_init(..) 1st"); + } else if(shallBeDetached) { (*_jvmHandle)->DetachCurrentThread(_jvmHandle); } } diff --git a/src/jogl/native/JoglCommon.h b/src/jogl/native/JoglCommon.h index 023b4be03..2aeaf7d1d 100644 --- a/src/jogl/native/JoglCommon.h +++ b/src/jogl/native/JoglCommon.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 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. + */ #ifndef JOGL_COMMON_H #define JOGL_COMMON_H 1 @@ -7,29 +34,25 @@ void JoglCommon_init(JNIEnv *env); -/** Set by JoglCommon_init */ -JavaVM *JoglCommon_GetJVMHandle(); - -/** Set by JoglCommon_init */ -int JoglCommon_GetJVMVersion(); - jchar* JoglCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); -/** env may be NULL, in which case JoglCommon_GetJNIEnv() is being used. */ void JoglCommon_FatalError(JNIEnv *env, const char* msg, ...); - -/** env may be NULL, in which case JoglCommon_GetJNIEnv() is being used. */ void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); /** * - * 1) Store jvmHandle and jvmVersion is done by 'JoglCommon_init(JNIEnv*)' - * and internally used by 'JoglCommon_GetJNIEnv(..)' and 'JoglCommon_ReleaseJNIEnv(..)'. + * 1) Init static jvmHandle, jvmVersion and clazz references + * from an early initialization call w/ valid 'JNIEnv * env' + + JoglCommon_init(env); + * * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv * + + int asDaemon = 0; int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(&shallBeDetached); + JNIEnv* env = JoglCommon_GetJNIEnv(asDaemon, &shallBeDetached); if(NULL==env) { DBG_PRINT("drawRect: null JNIEnv\n"); return; @@ -41,11 +64,13 @@ void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); .. your JNIEnv code here .. * - * 4) Detach thread from JVM, if required + * 4) Detach thread from JVM if required, i.e. not attached as daemon! + * Not recommended for recurring _daemon_ threads (performance) * - JoglCommon_ReleaseJNIEnv (shallBeDetached); + JoglCommon_ReleaseJNIEnv(shallBeDetached); */ -JNIEnv* JoglCommon_GetJNIEnv (int * shallBeDetached); +JNIEnv* JoglCommon_GetJNIEnv (int asDaemon, int * shallBeDetached); + void JoglCommon_ReleaseJNIEnv (int shallBeDetached); #endif diff --git a/src/jogl/native/libav/ffmpeg_impl_template.c b/src/jogl/native/libav/ffmpeg_impl_template.c index 44acfe46a..e86b2a542 100644 --- a/src/jogl/native/libav/ffmpeg_impl_template.c +++ b/src/jogl/native/libav/ffmpeg_impl_template.c @@ -1499,7 +1499,7 @@ JNIEXPORT jint JNICALL FF_FUNC(seek0) int64_t pts1 = (int64_t) (pos1 * (int64_t) time_base.den) / (1000 * (int64_t) time_base.num); if(pAV->verbose) { - fprintf(stderr, "SEEK: vid %d, aid %d, pos0 %d, pos1 %d, pts: %"PRId64" -> %"PRId64"\n", pAV->vid, pAV->aid, pos0, pos1, pts0, pts1); + fprintf(stderr, "SEEK: vid %d, aid %d, pos0 %"PRId64", pos1 %d, pts: %"PRId64" -> %"PRId64"\n", pAV->vid, pAV->aid, pos0, pos1, pts0, pts1); } int flags = 0; if(pos1 < pos0) { @@ -1508,7 +1508,7 @@ JNIEXPORT jint JNICALL FF_FUNC(seek0) int res = -2; if(HAS_FUNC(sp_av_seek_frame)) { if(pAV->verbose) { - fprintf(stderr, "SEEK.0: pre : s %d / %"PRId64" -> t %d / %"PRId64"\n", pos0, pts0, pos1, pts1); + fprintf(stderr, "SEEK.0: pre : s %"PRId64" / %"PRId64" -> t %d / %"PRId64"\n", pos0, pts0, pos1, pts1); } sp_av_seek_frame(pAV->pFormatCtx, streamID, pts1, flags); } else if(HAS_FUNC(sp_avformat_seek_file)) { diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m index 75917d2dc..7ce8c58cf 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m @@ -578,6 +578,7 @@ static const GLfloat gl_verts[] = { quirks, dedicatedFramePosSet, dedicatedFrameSizeSet, dedicatedLayoutSet, self, texWidth, texHeight, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, dFrame.origin.x, dFrame.origin.y, dFrame.size.width, dFrame.size.height); + (void)lRect; // silence if( dedicatedFrameSet ) { [super setFrame: dedicatedFrame]; diff --git a/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c b/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c index ec68a24aa..3166306ba 100644 --- a/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c +++ b/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c @@ -67,7 +67,7 @@ void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pAV) return; } int shallBeDetached = 0; - JNIEnv * env = JoglCommon_GetJNIEnv (&shallBeDetached); + JNIEnv * env = JoglCommon_GetJNIEnv (1 /* daemon */, &shallBeDetached); if(NULL!=env) { (*env)->CallVoidMethod(env, (jobject)pAV->jni_instance, jni_mid_updateAttributes, pAV->width, pAV->height, @@ -75,7 +75,8 @@ void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pAV) pAV->framerate, (uint32_t)(pAV->length*pAV->framerate), pAV->length, (*env)->NewStringUTF(env, pAV->videoCodec), (*env)->NewStringUTF(env, pAV->audioCodec) ); - JoglCommon_ReleaseJNIEnv (shallBeDetached); + // detaching thread not required - daemon + // JoglCommon_ReleaseJNIEnv(shallBeDetached); } } diff --git a/src/nativewindow/native/NativewindowCommon.c b/src/nativewindow/native/NativewindowCommon.c index ec7ee7728..e65f87272 100644 --- a/src/nativewindow/native/NativewindowCommon.c +++ b/src/nativewindow/native/NativewindowCommon.c @@ -8,41 +8,24 @@ static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; -void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...) -{ - char buffer[512]; - va_list ap; - - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); - - fprintf(stderr, "%s\n", buffer); - (*env)->FatalError(env, buffer); -} - -void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) -{ - char buffer[512]; - va_list ap; - - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); - - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} +static JavaVM *_jvmHandle = NULL; +static int _jvmVersion = 0; int NativewindowCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { + if(NULL==_jvmHandle) { + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); if(NULL==c) { - NativewindowCommon_FatalError(env, "Nativewindow: can't find %s", ClazzNameRuntimeException); + NativewindowCommon_FatalError(env, "Nativewindow: Can't find %s", ClazzNameRuntimeException); } runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); (*env)->DeleteLocalRef(env, c); if(NULL==runtimeExceptionClz) { - NativewindowCommon_FatalError(env, "Nativewindow: can't use %s", ClazzNameRuntimeException); + NativewindowCommon_FatalError(env, "Nativewindow: Can't use %s", ClazzNameRuntimeException); } #ifdef STDERR_TO_FILE FILE * old_stderr = stderr; @@ -54,6 +37,44 @@ int NativewindowCommon_init(JNIEnv *env) { return 0; } +void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...) +{ + char buffer[512]; + va_list ap; + + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); + + fprintf(stderr, "%s\n", buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + } + } +} + +void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) +{ + char buffer[512]; + va_list ap; + + if(NULL==_jvmHandle) { + NativewindowCommon_FatalError(env, "Nativewindow: NULL JVM handle, call NativewindowCommon_init 1st\n"); + return; + } + + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); + + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); + } + } +} + const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText) { if(NULL != jniEnv && NULL != clazz && NULL != jGetStrID) { jstring jstr = (jstring) (*jniEnv)->CallStaticObjectMethod(jniEnv, clazz, jGetStrID); @@ -75,45 +96,60 @@ const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass cla jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; - strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); - if (strChars != NULL) { - (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + if( NULL != env && 0 != str ) { + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } } return strChars; } -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int asDaemon, int * shallBeDetached) { +JNIEnv* NativewindowCommon_GetJNIEnv (int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; + if(NULL==_jvmHandle) { + fprintf(stderr, "Nativewindow GetJNIEnv: NULL JVM handle, call NativewindowCommon_init 1st\n"); + return NULL; + } + // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; + envRes = (*_jvmHandle)->GetEnv(_jvmHandle, (void **) &curEnv, _jvmVersion) ; if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM if( asDaemon ) { - envRes = (*jvmHandle)->AttachCurrentThreadAsDaemon(jvmHandle, (void**) &newEnv, NULL); + envRes = (*_jvmHandle)->AttachCurrentThreadAsDaemon(_jvmHandle, (void**) &newEnv, NULL); } else { - envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL); + envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL); } if( JNI_OK != envRes ) { - fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); + fprintf(stderr, "Nativewindow GetJNIEnv: Can't attach thread: %d\n", envRes); return NULL; } curEnv = newEnv; } else if( JNI_OK != envRes ) { // oops .. - fprintf(stderr, "can't GetEnv: %d\n", envRes); + fprintf(stderr, "Nativewindow GetJNIEnv: Can't GetEnv: %d\n", envRes); return NULL; } if (curEnv==NULL) { - fprintf(stderr, "env is NULL\n"); + fprintf(stderr, "Nativewindow GetJNIEnv: env is NULL\n"); return NULL; } *shallBeDetached = NULL != newEnv; return curEnv; } +void NativewindowCommon_ReleaseJNIEnv (int shallBeDetached) { + if(NULL == _jvmHandle) { + fprintf(stderr, "Nativewindow ReleaseJNIEnv: No JavaVM handle registered, call NativewindowCommon_init(..) 1st"); + } else if(shallBeDetached) { + (*_jvmHandle)->DetachCurrentThread(_jvmHandle); + } +} + int64_t NativewindowCommon_CurrentTimeMillis() { struct timeval tv; gettimeofday(&tv,NULL); diff --git a/src/nativewindow/native/NativewindowCommon.h b/src/nativewindow/native/NativewindowCommon.h index a23fad9fd..f19552e33 100644 --- a/src/nativewindow/native/NativewindowCommon.h +++ b/src/nativewindow/native/NativewindowCommon.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 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. + */ #ifndef NATIVEWINDOW_COMMON_H #define NATIVEWINDOW_COMMON_H 1 @@ -14,7 +41,39 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...); void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int asDaemon, int * shallBeDetached); +/** + * + * 1) Init static jvmHandle, jvmVersion and clazz references + * from an early initialization call w/ valid 'JNIEnv * env' + + NativewindowCommon_init(env); + + * + * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv + * + + int asDaemon = 0; + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(asDaemon, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("drawRect: null JNIEnv\n"); + return; + } + + * + * 3) Use JNIEnv .. + * + .. your JNIEnv code here .. + + * + * 4) Detach thread from JVM if required, i.e. not attached as daemon! + * Not recommended for recurring _daemon_ threads (performance) + * + NewtCommon_ReleaseJNIEnv(shallBeDetached); + */ +JNIEnv* NativewindowCommon_GetJNIEnv (int asDaemon, int * shallBeDetached); + +void NativewindowCommon_ReleaseJNIEnv (int shallBeDetached); int64_t NativewindowCommon_CurrentTimeMillis(); diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 6a7952eaf..4887cc3cf 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -75,11 +75,9 @@ static const char * const ClazzNameInsetsCstrSignature = "(IIII)V"; static jclass insetsClz = NULL; static jmethodID insetsCstr = NULL; -static int _initialized=0; - JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { - if(0==_initialized) { + if( NativewindowCommon_init(env) ) { jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -119,7 +117,6 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { if(NULL==runnableRunID) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); } - _initialized=1; } return JNI_TRUE; } @@ -775,12 +772,10 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns @interface MainRunnable : NSObject { - JavaVM *jvmHandle; - int jvmVersion; jobject runnableObj; } -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers; +- (id) initWithRunnable: (jobject)runnable; - (void) jRun; #ifdef DBG_LIFECYCLE @@ -794,10 +789,8 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns @implementation MainRunnable -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers +- (id) initWithRunnable: (jobject)runnable { - jvmHandle = jvm; - jvmVersion = jvmVers; runnableObj = runnable; return [super init]; } @@ -805,7 +798,7 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns - (void) jRun { int shallBeDetached = 0; - JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, 1 /* asDaemon */, &shallBeDetached); + JNIEnv* env = NativewindowCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env)); if(NULL!=env) { DBG_PRINT2("MainRunnable.1.0\n"); @@ -813,11 +806,9 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns DBG_PRINT2("MainRunnable.1.1\n"); (*env)->DeleteGlobalRef(env, runnableObj); - if (shallBeDetached) { - DBG_PRINT2("MainRunnable.1.3\n"); - // Keep attached on main thread ! - // (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + DBG_PRINT2("MainRunnable.1.3\n"); + // detaching thread not required - daemon + // NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } DBG_PRINT2("MainRunnable.X\n"); } @@ -861,17 +852,8 @@ static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayI if ( forkOnMain ) { jobject runnableObj = (*env)->NewGlobalRef(env, runnable); - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; - - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } else { - jvmVersion = (*env)->GetVersion(env); - } - DBG_PRINT2( "RunOnThread.1.0\n"); - MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj jvmHandle: jvmHandle jvmVersion: jvmVersion]; + MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj]; if( onMain ) { [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; diff --git a/src/nativewindow/native/win32/GDImisc.c b/src/nativewindow/native/win32/GDImisc.c index e28f68e7d..bec1d4922 100644 --- a/src/nativewindow/native/win32/GDImisc.c +++ b/src/nativewindow/native/win32/GDImisc.c @@ -487,7 +487,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindo JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 (JNIEnv *env, jclass gdiClazz) { - if(NativewindowCommon_init(env)) { + if( NativewindowCommon_init(env) ) { jclass c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't find %s", ClazzNamePoint); diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 5e6909f6e..247dc1311 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -113,68 +113,56 @@ static jmethodID pointCstr = NULL; static void _initClazzAccess(JNIEnv *env) { jclass c; - if(!NativewindowCommon_init(env)) return; - - getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;"); - if(NULL==getCurrentThreadNameID) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName"); - } - dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V"); - if(NULL==dumpStackID) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack"); - } - - c = (*env)->FindClass(env, ClazzNameBuffers); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); - } - clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==clazzBuffers) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers); - } - c = (*env)->FindClass(env, ClazzNameByteBuffer); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer); - } - clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer); - } - - cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers, - ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); - if(NULL==cstrBuffers) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s", - ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); - } + if( NativewindowCommon_init(env) ) { + getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;"); + if(NULL==getCurrentThreadNameID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName"); + } + dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V"); + if(NULL==dumpStackID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack"); + } - c = (*env)->FindClass(env, ClazzNamePoint); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint); - } - pointClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==pointClz) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint); - } - pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); - if(NULL==pointCstr) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s", - ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); - } -} + c = (*env)->FindClass(env, ClazzNameBuffers); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); + } + clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==clazzBuffers) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers); + } + c = (*env)->FindClass(env, ClazzNameByteBuffer); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer); + } + clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer); + } -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; + cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers, + ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); + if(NULL==cstrBuffers) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s", + ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); + } -static void setupJVMVars(JNIEnv * env) { - if( NULL != env && NULL == jvmHandle ) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + c = (*env)->FindClass(env, ClazzNamePoint); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint); + } + pointClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==pointClz) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint); + } + pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); + if(NULL==pointCstr) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s", + ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } - jvmVersion = (*env)->GetVersion(env); } } @@ -201,8 +189,8 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) (int)e->request_code, (int)e->minor_code, reqCodeStr); fflush(stderr); - if( NULL != jvmHandle && ( errorHandlerDebug || errorHandlerThrowException ) ) { - jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, 0 /* asDaemon */, &shallBeDetached); + if( errorHandlerDebug || errorHandlerThrowException ) { + jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached); if(NULL == jniEnv) { fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); fflush(stderr); @@ -219,9 +207,7 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); } - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } } @@ -233,7 +219,6 @@ static void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, if(onoff) { if(force || NULL==origErrorHandler) { XErrorHandler prevErrorHandler; - setupJVMVars(env); prevErrorHandler = XSetErrorHandler(x11ErrorHandler); if(x11ErrorHandler != prevErrorHandler) { // if forced don't overwrite w/ orig w/ our handler origErrorHandler = prevErrorHandler; @@ -265,14 +250,10 @@ static int x11IOErrorHandler(Display *dpy) fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr); fflush(stderr); - if( NULL != jvmHandle ) { - jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, 0 /* asDaemon */, &shallBeDetached); - if (NULL != jniEnv) { - NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } - } + jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached); + if (NULL != jniEnv) { + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr); + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } if(NULL!=origIOErrorHandler) { origIOErrorHandler(dpy); @@ -283,7 +264,6 @@ static int x11IOErrorHandler(Display *dpy) static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { if(onoff) { if(NULL==origIOErrorHandler) { - setupJVMVars(env); origIOErrorHandler = XSetIOErrorHandler(x11IOErrorHandler); } } else { diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index c6fd805a5..130b2e3e3 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -113,18 +113,6 @@ static void setJavaWindowObject(JNIEnv *env, jobject newJavaWindowObject, NewtVi DBG_PRINT( "setJavaWindowObject.2: View %p - Set new javaWindowObject %p\n", view, newJavaWindowObject); jobject globJavaWindowObject = (*env)->NewGlobalRef(env, newJavaWindowObject); [view setJavaWindowObject: globJavaWindowObject]; - { - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; - - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } else { - jvmVersion = (*env)->GetVersion(env); - } - [view setJVMHandle: jvmHandle]; - [view setJVMVersion: jvmVersion]; - } } DBG_PRINT( "setJavaWindowObject.X: View %p\n", view); } @@ -979,6 +967,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_close0 BOOL isNewtWin = [mWin isKindOfClass:[NewtMacWindow class]]; NSWindow *pWin = [mWin parentWindow]; DBG_PRINT( "windowClose.0 - %p [isNSWindow %d, isNewtWin %d], parent %p\n", mWin, isNSWin, isNewtWin, pWin); + (void)isNSWin; // silence if( !isNewtWin ) { NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); return; diff --git a/src/newt/native/NewtCommon.c b/src/newt/native/NewtCommon.c index c294b6e0b..231d6182f 100644 --- a/src/newt/native/NewtCommon.c +++ b/src/newt/native/NewtCommon.c @@ -5,17 +5,43 @@ static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; +static JavaVM *_jvmHandle = NULL; +static int _jvmVersion = 0; + +void NewtCommon_init(JNIEnv *env) { + if(NULL==_jvmHandle) { + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + NewtCommon_FatalError(env, "NEWT: Can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + NewtCommon_FatalError(env, "NEWT: Can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + NewtCommon_FatalError(env, "NEWT: Can't use %s", ClazzNameRuntimeException); + } + } +} + void NewtCommon_FatalError(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); - fprintf(stderr, "%s\n", buffer); - (*env)->FatalError(env, buffer); + fprintf(stderr, "%s\n", buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + } + } } void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) @@ -23,23 +49,18 @@ void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if(NULL==_jvmHandle) { + NewtCommon_FatalError(env, "NEWT: NULL JVM handle, call NewtCommon_init 1st\n"); + return; + } - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); -void NewtCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { - jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); - if(NULL==c) { - NewtCommon_FatalError(env, "NEWT: can't find %s", ClazzNameRuntimeException); - } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==runtimeExceptionClz) { - NewtCommon_FatalError(env, "NEWT: can't use %s", ClazzNameRuntimeException); + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); } } } @@ -65,42 +86,57 @@ const char * NewtCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmet jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; - strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); - if (strChars != NULL) { - (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + if( NULL != env && 0 != str ) { + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } } return strChars; } -JNIEnv* NewtCommon_GetJNIEnv(JavaVM * jvmHandle, int jvmVersion, int asDaemon, int * shallBeDetached) { +JNIEnv* NewtCommon_GetJNIEnv(int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; + if(NULL==_jvmHandle) { + fprintf(stderr, "NEWT GetJNIEnv: NULL JVM handle, call NewtCommon_init 1st\n"); + return NULL; + } + // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; + envRes = (*_jvmHandle)->GetEnv(_jvmHandle, (void **) &curEnv, _jvmVersion) ; if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM if( asDaemon ) { - envRes = (*jvmHandle)->AttachCurrentThreadAsDaemon(jvmHandle, (void**) &newEnv, NULL); + envRes = (*_jvmHandle)->AttachCurrentThreadAsDaemon(_jvmHandle, (void**) &newEnv, NULL); } else { - envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL); + envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL); } if( JNI_OK != envRes ) { - fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); + fprintf(stderr, "NEWT GetJNIEnv: Can't attach thread: %d\n", envRes); return NULL; } curEnv = newEnv; } else if( JNI_OK != envRes ) { // oops .. - fprintf(stderr, "can't GetEnv: %d\n", envRes); + fprintf(stderr, "NEWT GetJNIEnv: Can't GetEnv: %d\n", envRes); return NULL; } if (curEnv==NULL) { - fprintf(stderr, "env is NULL\n"); + fprintf(stderr, "NEWT GetJNIEnv: env is NULL\n"); return NULL; } *shallBeDetached = NULL != newEnv; return curEnv; } +void NewtCommon_ReleaseJNIEnv (int shallBeDetached) { + if(NULL == _jvmHandle) { + fprintf(stderr, "NEWT ReleaseJNIEnv: No JavaVM handle registered, call NewtCommon_init(..) 1st"); + } else if(shallBeDetached) { + (*_jvmHandle)->DetachCurrentThread(_jvmHandle); + } +} + diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index 9cc9e93a6..43db72b5b 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -42,23 +42,18 @@ void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); /** * - * 1) Store jvmHandle and jvmVersion + * 1) Init static jvmHandle, jvmVersion and clazz references + * from an early initialization call w/ valid 'JNIEnv * env' - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; - - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } else { - jvmVersion = (*env)->GetVersion(env); - } + NewtCommon_init(env); * * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv * + int asDaemon = 0; int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(asDaemon, &shallBeDetached); if(NULL==env) { DBG_PRINT("drawRect: null JNIEnv\n"); return; @@ -70,12 +65,13 @@ void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); .. your JNIEnv code here .. * - * 4) Detach thread from JVM, if required + * 4) Detach thread from JVM if required, i.e. not attached as daemon! + * Not recommended for recurring _daemon_ threads (performance) * - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); */ -JNIEnv* NewtCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int asDaemon, int * shallBeDetached); +JNIEnv* NewtCommon_GetJNIEnv (int asDaemon, int * shallBeDetached); + +void NewtCommon_ReleaseJNIEnv (int shallBeDetached); #endif diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index daf75bec7..8f6362ac2 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -53,10 +53,6 @@ { jobject javaWindowObject; - // This is set while messages are being dispatched and cleared afterward - JavaVM *jvmHandle; - int jvmVersion; - volatile BOOL destroyNotifySent; volatile int softLockCount; pthread_mutex_t softLockSync; @@ -80,12 +76,6 @@ #endif - (void) dealloc; -/* Set during event dispatching cycle */ -- (void) setJVMHandle: (JavaVM*) vm; -- (JavaVM*) getJVMHandle; -- (void) setJVMVersion: (int) ver; -- (int) getJVMVersion; - /* Register or deregister (NULL) the java Window object, ie, if NULL, no events are send */ - (void) setJavaWindowObject: (jobject) javaWindowObj; diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 5ccd9c658..b4133ac7e 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -193,8 +193,6 @@ static jmethodID windowRepaintID = NULL; id res = [super initWithFrame:frameRect]; javaWindowObject = NULL; - jvmHandle = NULL; - jvmVersion = 0; destroyNotifySent = NO; softLockCount = 0; @@ -244,25 +242,6 @@ static jmethodID windowRepaintID = NULL; [super dealloc]; } -- (void) setJVMHandle: (JavaVM*) vm -{ - jvmHandle = vm; -} -- (JavaVM*) getJVMHandle -{ - return jvmHandle; -} - -- (void) setJVMVersion: (int) ver -{ - jvmVersion = ver; -} - -- (int) getJVMVersion -{ - return jvmVersion; -} - - (void) setJavaWindowObject: (jobject) javaWindowObj { javaWindowObject = javaWindowObj; @@ -342,7 +321,7 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, 1 /* asDaemon */, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("drawRect: null JNIEnv\n"); return; @@ -354,9 +333,8 @@ static jmethodID windowRepaintID = NULL; dirtyRect.origin.x, viewFrame.size.height - dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height); - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (void) viewDidHide @@ -366,7 +344,7 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, 1 /* asDaemon */, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("viewDidHide: null JNIEnv\n"); return; @@ -374,9 +352,8 @@ static jmethodID windowRepaintID = NULL; (*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE, JNI_FALSE); - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); [super viewDidHide]; } @@ -388,7 +365,7 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, 1 /* asDaemon */, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("viewDidUnhide: null JNIEnv\n"); return; @@ -396,9 +373,8 @@ static jmethodID windowRepaintID = NULL; (*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE, JNI_TRUE); - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); [super viewDidUnhide]; } @@ -645,14 +621,9 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [self getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } else { - env = NULL; - } + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { - DBG_PRINT("sendMouseEvent: JVM %p JNIEnv %p\n", jvmHandle, env); + DBG_PRINT("sendMouseEvent: null JNIEnv\n"); return; } jint javaMods[] = { 0 } ; @@ -700,9 +671,8 @@ static jmethodID windowRepaintID = NULL; (jint) location.x, (jint) location.y, javaButtonNum, scrollDeltaY); - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p @@ -754,14 +724,9 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [self getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } else { - env = NULL; - } + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { - DBG_PRINT("sendKeyEvent: JVM %p JNIEnv %p\n", jvmHandle, env); + DBG_PRINT("sendKeyEvent: null JNIEnv\n"); return; } @@ -792,9 +757,8 @@ static jmethodID windowRepaintID = NULL; evType, javaMods, keyCode, keyChar, keyChar); } - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } @end @@ -1038,23 +1002,16 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [newtView getJVMHandle]; - JNIEnv* env; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } else { - env = NULL; - } + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { - DBG_PRINT("focusChanged: JVM %p JNIEnv %p\n", jvmHandle, env); + DBG_PRINT("focusChanged: null JNIEnv\n"); return; } (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE); - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (void) keyDown: (NSEvent*) theEvent @@ -1147,37 +1104,31 @@ static jmethodID windowRepaintID = NULL; - (void)windowDidResize: (NSNotification*) notification { - JNIEnv* env = NULL; jobject javaWindowObject = NULL; int shallBeDetached = 0; - JavaVM *jvmHandle = NULL; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if( NULL == env ) { + DBG_PRINT("windowDidResize: null JNIEnv\n"); + return; + } NewtView* newtView = (NewtView *) [self contentView]; if( [newtView isKindOfClass:[NewtView class]] ) { javaWindowObject = [newtView getJavaWindowObject]; - if (javaWindowObject != NULL) { - jvmHandle = [newtView getJVMHandle]; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } - } } + if( NULL != javaWindowObject ) { + // update insets on every window resize for lack of better hook place + [self updateInsets: env jwin:javaWindowObject]; - // update insets on every window resize for lack of better hook place - [self updateInsets: env jwin:javaWindowObject]; - - if( NULL != env && NULL != javaWindowObject ) { NSRect frameRect = [self frame]; NSRect contentRect = [self contentRectForFrameRect: frameRect]; (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_FALSE, (jint) contentRect.size.width, (jint) contentRect.size.height, JNI_FALSE); - - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (void)windowDidMove: (NSNotification*) notification @@ -1192,15 +1143,9 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [newtView getJVMHandle]; - JNIEnv* env; - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } else { - env = NULL; - } + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { - DBG_PRINT("windowDidMove: JVM %p JNIEnv %p\n", jvmHandle, env); + DBG_PRINT("windowDidMove: null JNIEnv\n"); return; } @@ -1208,9 +1153,8 @@ static jmethodID windowRepaintID = NULL; p0 = [self getLocationOnScreen: p0]; (*env)->CallVoidMethod(env, javaWindowObject, positionChangedID, JNI_FALSE, (jint) p0.x, (jint) p0.y); - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (BOOL)windowShouldClose: (id) sender @@ -1226,13 +1170,12 @@ static jmethodID windowRepaintID = NULL; - (BOOL) windowClosingImpl: (BOOL) force { jboolean closed = JNI_FALSE; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* newtView = (NewtView *) [self contentView]; if( ! [newtView isKindOfClass:[NewtView class]] ) { return NO; } - + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [newtView cursorHide: NO enter: -1]; if( false == [newtView getDestroyNotifySent] ) { @@ -1240,26 +1183,16 @@ static jmethodID windowRepaintID = NULL; DBG_PRINT( "*************** windowWillClose.0: %p\n", (void *)(intptr_t)javaWindowObject); if (javaWindowObject == NULL) { DBG_PRINT("windowWillClose: null javaWindowObject\n"); + [pool release]; return NO; } int shallBeDetached = 0; - JavaVM *jvmHandle = [newtView getJVMHandle]; - JNIEnv* env = NULL; -NS_DURING - if( NULL != jvmHandle ) { - env = NewtCommon_GetJNIEnv(jvmHandle, [newtView getJVMVersion], 1 /* asDaemon */, &shallBeDetached); - } -NS_HANDLER - jvmHandle = NULL; - env = NULL; - [newtView setJVMHandle: NULL]; - DBG_PRINT("windowWillClose: JVMHandler Exception\n"); -NS_ENDHANDLER - DBG_PRINT("windowWillClose: JVM %p JNIEnv %p\n", jvmHandle, env); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { + DBG_PRINT("windowWillClose: null JNIEnv\n"); + [pool release]; return NO; } - [newtView setDestroyNotifySent: true]; // earmark assumption of being closed closed = (*env)->CallBooleanMethod(env, javaWindowObject, windowDestroyNotifyID, force ? JNI_TRUE : JNI_FALSE); if(!force && !closed) { @@ -1267,9 +1200,8 @@ NS_ENDHANDLER [newtView setDestroyNotifySent: false]; } - /* if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } */ + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); DBG_PRINT( "*************** windowWillClose.X: %p, closed %d\n", (void *)(intptr_t)javaWindowObject, (int)closed); } else { DBG_PRINT( "*************** windowWillClose (skip)\n"); -- cgit v1.2.3