diff options
Diffstat (limited to 'src')
9 files changed, 610 insertions, 106 deletions
diff --git a/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java index e4046ac..05192d3 100644 --- a/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java @@ -50,6 +50,10 @@ public final class JavaCallbackEmitter { final JavaType setFuncUserParamJType; final String setFuncUserParamTypeName; final String setFuncUserParamArgName; + final boolean userParamIsKey; + final boolean userParamIsCompound; + final boolean userParamIsMappedToID; + final String userParamIDMapInstanceName; final boolean customKeyClass; final String KeyClassName; @@ -77,6 +81,23 @@ public final class JavaCallbackEmitter { setFuncUserParamTypeName = setFuncUserParamJType.getName(); setFuncUserParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx); + userParamIsKey = info.setFuncKeyIndices.contains(info.setFuncUserParamIdx); + if( !setFuncUserParamJType.isLong() ) { + if( setFuncUserParamJType.isCompoundTypeWrapper() ) { + userParamIsCompound = true; + userParamIsMappedToID = false; + userParamIDMapInstanceName = null; + } else { + userParamIsCompound = false; + userParamIsMappedToID = true; + userParamIDMapInstanceName = userParamIsKey ? lowIfaceName+"UserObjIDMap" : null; + } + } else { + userParamIsCompound = false; + userParamIsMappedToID = false; + userParamIDMapInstanceName = null; + } + if( null != javaCallback.setFuncKeyClassName ) { customKeyClass = true;; KeyClassName = javaCallback.setFuncKeyClassName; @@ -88,36 +109,6 @@ public final class JavaCallbackEmitter { } } - public void emitJavaSetFuncPreCall(final CodeUnit unit) { - unit.emitln(" synchronized( "+lockInstanceName+" ) {"); - unit.emit (" final long nativeUserParam = "); - if( setFuncUserParamJType.isLong() ) { - unit.emitln(" "+setFuncUserParamArgName+";"); - } else if( setFuncUserParamJType.isCompoundTypeWrapper() ) { - unit.emitln(" null != "+setFuncUserParamArgName+" ? "+setFuncUserParamArgName+".getDirectBufferAddress() : 0;"); - } else { - unit.emitln(""+jcbNextIDVarName+"++;"); - unit.emitln(" if( 0 >= "+jcbNextIDVarName+" ) { "+jcbNextIDVarName+" = 1; }"); - } - unit.emitln(" if( null != "+setFuncCBArgName+" ) {"); - unit.emitln(" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, true).toString()+ - "new "+DataClassName+"("+setFuncCBArgName+", "+setFuncUserParamArgName+"));"); - unit.emitln(" }"); - unit.emitln(); - } - - public void emitJavaSetFuncPostCall(final CodeUnit unit) { - unit.emitln(" if( null == "+setFuncCBArgName+" ) {"); - unit.emitln(" // callback released (null func) -> release a previously mapped instance "); - if( useDataMap ) { - unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" ) );"); - } else { - unit.emitln(" release"+capIfaceName+"();"); - } - unit.emitln(" }"); - unit.emitln(" } // synchronized "); - } - public void emitJavaAdditionalCode(final CodeUnit unit, final boolean isInterface) { if( isInterface ) { if( useDataMap ) { @@ -213,7 +204,14 @@ public final class JavaCallbackEmitter { emitJavaBriefAPIDoc(unit, "Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to "); unit.emitln(" public final void release"+capIfaceName+"("+KeyClassName+" key) {"); unit.emitln(" synchronized( "+lockInstanceName+" ) {"); - unit.emitln(" /* final "+DataClassName+" value = */ "+dataMapInstanceName+".remove(key);"); + if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" "+DataClassName+" value = "+dataMapInstanceName+".remove(key);"); + unit.emitln(" if( null != value ) {"); + unit.emitln(" "+userParamIDMapInstanceName+".remove(value.paramID);"); + unit.emitln(" }"); + } else { + unit.emitln(" /* "+DataClassName+" value = */ "+dataMapInstanceName+".remove(key);"); + } unit.emitln(" }"); unit.emitln(" }"); unit.emitln(); @@ -248,6 +246,9 @@ public final class JavaCallbackEmitter { unit.emitln(" public final void release"+capIfaceName+"() {"); unit.emitln(" synchronized( "+lockInstanceName+" ) {"); unit.emitln(" // final "+DataClassName+" value = "+dataInstanceName+";"); + if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" "+userParamIDMapInstanceName+".remove(dataInstanceName.paramID);"); + } unit.emitln(" "+dataInstanceName+" = null;"); unit.emitln(" }"); unit.emitln(" }"); @@ -256,11 +257,27 @@ public final class JavaCallbackEmitter { unit.emitln(" private final void add"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, true).toString()+DataClassName+" value) {"); if( useDataMap ) { unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+");"); - unit.emitln(" /* final "+DataClassName+" old = */ "+dataMapInstanceName+".put(key, value);"); + if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" final "+DataClassName+" old = "+dataMapInstanceName+".put(key, value);"); + } else { + unit.emitln(" /* final "+DataClassName+" old = */ "+dataMapInstanceName+".put(key, value);"); + } } else { - unit.emitln(" // final "+DataClassName+" old = "+dataInstanceName+";"); + if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" final "+DataClassName+" old = "+dataInstanceName+";"); + } else { + unit.emitln(" // final "+DataClassName+" old = "+dataInstanceName+";"); + } unit.emitln(" "+dataInstanceName+" = value;"); } + if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" if( null != old ) {"); + unit.emitln(" "+userParamIDMapInstanceName+".remove(old.paramID);"); + unit.emitln(" }"); + unit.emitln(" if( null != value.param ) {"); + unit.emitln(" "+userParamIDMapInstanceName+".put(value.paramID, value.param);"); + unit.emitln(" }"); + } unit.emitln(" }"); unit.emitln(); if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) { @@ -272,6 +289,9 @@ public final class JavaCallbackEmitter { } else { unit.emitln(" private static "+DataClassName+" "+dataInstanceName+" = null;"); } + if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" private static final LongObjectHashMap "+userParamIDMapInstanceName+" = new LongObjectHashMap();"); + } unit.emitln(" private static long "+jcbNextIDVarName+" = 1;"); unit.emitln(" private static final Object "+lockInstanceName+" = new Object();"); unit.emitln(); @@ -390,9 +410,19 @@ public final class JavaCallbackEmitter { unit.emitln(" // userParamArgCType "+setFuncUserParamCType); unit.emitln(" // userParamArgJType "+setFuncUserParamJType); unit.emitln(" final "+info.cbFuncTypeName+" func;"); + if( userParamIsMappedToID ) { + unit.emitln(" final long paramID;"); + } unit.emitln(" final "+setFuncUserParamTypeName+" param;"); - unit.emitln(" "+DataClassName+"("+info.cbFuncTypeName+" func, "+setFuncUserParamTypeName+" param) {"); + unit.emit (" "+DataClassName+"(final "+info.cbFuncTypeName+" func, "); + if( userParamIsMappedToID ) { + unit.emit("final long paramID, "); + } + unit.emitln("final "+setFuncUserParamTypeName+" param) {"); unit.emitln(" this.func = func;"); + if( userParamIsMappedToID ) { + unit.emitln(" this.paramID = paramID;"); + } unit.emitln(" this.param = param;"); unit.emitln(" }"); unit.emitln(" }"); @@ -426,6 +456,45 @@ public final class JavaCallbackEmitter { buf.append("this.getClass(), \"" + getJavaStaticCallbackSignature()+ "\", nativeUserParam"); return 3; } + + public void emitJavaSetFuncPreCall(final CodeUnit unit) { + unit.emitln(" final long nativeUserParam;"); + unit.emitln(" synchronized( "+lockInstanceName+" ) {"); + if( setFuncUserParamJType.isLong() ) { + unit.emitln(" nativeUserParam = "+setFuncUserParamArgName+";"); + } else { + unit.emitln(" if( null != "+setFuncUserParamArgName+" ) {"); + if( setFuncUserParamJType.isCompoundTypeWrapper() ) { + // userParamIsCompound == true + unit.emitln(" nativeUserParam = "+setFuncUserParamArgName+".getDirectBufferAddress();"); + } else { + // userParamIsMappedToID == true + unit.emitln(" nativeUserParam = "+jcbNextIDVarName+"++;"); + unit.emitln(" if( 0 >= "+jcbNextIDVarName+" ) { "+jcbNextIDVarName+" = 1; }"); + } + unit.emitln(" } else {"); + unit.emitln(" nativeUserParam = 0;"); + unit.emitln(" }"); + } + unit.emitln(" if( null != "+setFuncCBArgName+" ) {"); + unit.emit (" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, true).toString()+ + "new "+DataClassName+"("+setFuncCBArgName+", "); + if( userParamIsMappedToID ) { + unit.emit("nativeUserParam, "); + } + unit.emitln(setFuncUserParamArgName+"));"); + unit.emitln(" } else { "); + unit.emitln(" // release a previously mapped instance "); + if( useDataMap ) { + unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" ) );"); + } else { + unit.emitln(" release"+capIfaceName+"();"); + } + unit.emitln(" }"); + unit.emitln(" } // synchronized "); + unit.emitln(); + } + private final void emitJavaStaticCallback(final CodeUnit unit) { unit.emitln(" /** Static callback invocation, dispatching to "+info.cbSimpleClazzName+" for callback <br> <code>"+ info.cbFuncType.toString(info.cbFuncTypeName, false, true)+"</code> */"); @@ -436,7 +505,7 @@ public final class JavaCallbackEmitter { if( !cType.isVoid() ) { if( 0 < consumedCount ) { unit.emit(", "); } if( idx == info.cbFuncUserParamIdx ) { - unit.emit("long nativeUserParamPtr"); + unit.emit("long nativeUserParam"); if( jType.isCompoundTypeWrapper() ) { mapNativePtrToCompound[0] = true; origUserParamJType[0] = jType; @@ -450,11 +519,19 @@ public final class JavaCallbackEmitter { } } ); unit.emitln(") {"); + final boolean useParamLocal[] = { false }; if( mapNativePtrToCompound[0] ) { - unit.emitln(" final "+origUserParamJType[0]+" "+info.cbFuncUserParamName+" = "+origUserParamJType[0]+".derefPointer(nativeUserParamPtr);"); + unit.emitln(" final "+origUserParamJType[0]+" "+info.cbFuncUserParamName+" = "+origUserParamJType[0]+".derefPointer(nativeUserParam);"); + useParamLocal[0] = true; + } else if( userParamIsMappedToID && userParamIsKey ) { + unit.emitln(" final Object "+info.cbFuncUserParamName+";"); } unit.emitln(" final "+DataClassName+" value;"); unit.emitln(" synchronized( "+lockInstanceName+" ) {"); + if( userParamIsMappedToID && userParamIsKey && !mapNativePtrToCompound[0] ) { + unit.emitln(" "+info.cbFuncUserParamName+" = "+userParamIDMapInstanceName+".get(nativeUserParam);"); + useParamLocal[0] = true; + } if( useDataMap ) { unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+info.cbFuncBinding.getJavaCallSelectArguments(new StringBuilder(), info.cbFuncKeyIndices, false).toString()+");"); unit.emitln(" value = "+dataMapInstanceName+".get(key);"); @@ -478,7 +555,7 @@ public final class JavaCallbackEmitter { info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> { if( !cType.isVoid() ) { if( 0 < consumedCount ) { unit.emit(", "); } - if( idx == info.cbFuncUserParamIdx && !mapNativePtrToCompound[0] ) { + if( idx == info.cbFuncUserParamIdx && !useParamLocal[0] ) { unit.emit("value.param"); } else { unit.emit(name); diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index 07bd55d..88cff27 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -1473,7 +1473,7 @@ public class JavaEmitter implements GlueEmitter { funcType.toString(jcbd.cbFuncTypeName, false, true)); } final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, jcbi0.staticCBMethodSignature, - funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx, jcbi0.cbFuncKeyIndices, + funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx, jcbd.cbFuncKeyIndices, jcbd.setFuncName, jcbd.setFuncUserParamIdx, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName); cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1); LOG.log(INFO, "JavaCallbackInfo: Reusing {0} -> {1}", jcbd.setFuncName, jcbi0); diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java index fe4f82a..1b510c0 100644 --- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java @@ -604,7 +604,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { javaCallbackEmitter.emitJavaSetFuncPreCall(unit); } if (!returnType.isVoid()) { - unit.emit(" "); + unit.emit(" "); if (returnType.isCompoundTypeWrapper() || returnType.isNIOBuffer()) { unit.emitln("final ByteBuffer _res;"); @@ -622,9 +622,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { } if (needsResultAssignment) { - unit.emit(" _res = "); + unit.emit(" _res = "); } else { - unit.emit(" "); + unit.emit(" "); if (!returnType.isVoid()) { unit.emit("return "); } @@ -633,11 +633,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { emitCall(binding); unit.emitln(); - if( null != javaCallbackEmitter ) { - unit.emitln(); - javaCallbackEmitter.emitJavaSetFuncPostCall(unit); - } - emitPostCallCleanup(binding); emitPrologueOrEpilogue(epilogue); if (needsResultAssignment) { diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java b/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java index bc04977..90e01df 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java @@ -33,7 +33,10 @@ import java.util.Set; import com.jogamp.common.os.NativeLibrary; import com.jogamp.gluegen.test.junit.generation.Bindingtest2.ALBUFFERCALLBACKTYPESOFT; +import com.jogamp.gluegen.test.junit.generation.Bindingtest2.ALEVENTPROCSOFT; import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlBufferCallback0Key; +import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlEventCallback0Key; +import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlEventCallback1Key; import com.jogamp.gluegen.test.junit.generation.Bindingtest2.MessageCallback11aKey; import com.jogamp.gluegen.test.junit.generation.Bindingtest2.MessageCallback11bKey; import com.jogamp.gluegen.test.junit.generation.Bindingtest2.T2_CallbackFunc01; @@ -363,6 +366,48 @@ public class Test4JavaCallback extends BaseClass { Assert.assertEquals(false, keys.contains(buffer3Key)); } + // Switch the callback function for buffer2 -> myCallback01, myUserParam02 + { + // pre-condition + Assert.assertEquals(true, bt2.isAlBufferCallback0Mapped(buffer1Key)); + Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer2Key)); + Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer3Key)); + Assert.assertEquals(myUserParam01, bt2.getAlBufferCallback0UserParam(buffer1Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer2Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer3Key)); + Assert.assertEquals(myCallback01, bt2.getAlBufferCallback0(buffer1Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer2Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer3Key)); + Assert.assertEquals(1, bt2.getAlBufferCallback0Keys().size()); + } + bt2.alBufferCallback0(buffer1, 0, 0, myCallback02, myUserParam02); + { + // post-state + Assert.assertEquals(true, bt2.isAlBufferCallback0Mapped(buffer1Key)); + Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer2Key)); + Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer3Key)); + Assert.assertEquals(myUserParam02, bt2.getAlBufferCallback0UserParam(buffer1Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer2Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer3Key)); + Assert.assertEquals(myCallback02, bt2.getAlBufferCallback0(buffer1Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer2Key)); + Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer3Key)); + } + { + myUserParam01.j = 0; + myUserParam01.buffer = 0; + myUserParam02.j = 0; + myUserParam02.buffer = 0; + bt2.alBufferCallback0Inject(buffer1, 2, 10); // buffer1 -> myCallback01, myUserParam01 + Assert.assertEquals( 2*10+2, id_res[0]); + Assert.assertEquals( 1, myUserParam01.i); + Assert.assertEquals( 0, myUserParam01.j); + Assert.assertEquals( 0, myUserParam01.buffer); + Assert.assertEquals( 2, myUserParam02.i); + Assert.assertEquals( 2*10+2, myUserParam02.j); + Assert.assertEquals( 1, myUserParam02.buffer); + } + // Just release the buffer1 callback and mapped resources bt2.alBufferCallback0(buffer1, 0, 0, null, null); // usrptr is not key, only buffer is key! Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer1Key)); @@ -383,14 +428,19 @@ public class Test4JavaCallback extends BaseClass { } { + id_res[0] = 0; + myUserParam01.j = 0; + myUserParam01.buffer = 0; + myUserParam02.j = 0; + myUserParam02.buffer = 0; bt2.alBufferCallback0Inject(buffer2, 1, 10); // unmapped, no change in data - Assert.assertEquals( 1+ 10+2, id_res[0]); + Assert.assertEquals( 0, id_res[0]); Assert.assertEquals( 1, myUserParam01.i); - Assert.assertEquals(11+101+1, myUserParam01.j); - Assert.assertEquals( 1, myUserParam01.buffer); + Assert.assertEquals( 0, myUserParam01.j); + Assert.assertEquals( 0, myUserParam01.buffer); Assert.assertEquals( 2, myUserParam02.i); - Assert.assertEquals( 1+ 10+2, myUserParam02.j); - Assert.assertEquals( 2, myUserParam02.buffer); + Assert.assertEquals( 0, myUserParam02.j); + Assert.assertEquals( 0, myUserParam02.buffer); } } @@ -882,6 +932,264 @@ public class Test4JavaCallback extends BaseClass { } /** + * Test Bindingtest2 with ALEVENTPROCSOFT JavaCallback + * on alEventCallback0(..) having the 'Object userParam` as single key. + */ + @Test + public void chapter05a() throws Exception { + final Bindingtest2 bt2 = new Bindingtest2Impl(); + + final int[] id_res = { -1 }; + final String[] msg_res = { null }; + final ALEVENTPROCSOFT myCallback01 = new ALEVENTPROCSOFT() { + @Override + public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) { + id_res[0] = object; + msg_res[0] = message; + System.err.println("chapter05a.myCallback01: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+ + Integer.toHexString(System.identityHashCode(userParam))); + } + }; + final ALEVENTPROCSOFT myCallback02 = new ALEVENTPROCSOFT() { + @Override + public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) { + id_res[0] = 1000 * object; + msg_res[0] = message; + System.err.println("chapter05a.myCallback02: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+ + Integer.toHexString(System.identityHashCode(userParam))); + } + }; + final Object myUserParam01 = new Object(); + final Object myUserParam02 = new Object(); + final AlEventCallback0Key myKey01 = new AlEventCallback0Key(myUserParam01); + final AlEventCallback0Key myKey02 = new AlEventCallback0Key(myUserParam02); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02)); + + bt2.alEventCallback0(myCallback01, myUserParam01); + Assert.assertEquals(true, bt2.isAlEventCallback0Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02)); + { + final Set<AlEventCallback0Key> keys = bt2.getAlEventCallback0Keys(); + Assert.assertEquals(1, keys.size()); + Assert.assertEquals(true, keys.contains(myKey01)); + Assert.assertEquals(false, keys.contains(myKey02)); + } + Assert.assertEquals(myCallback01, bt2.getAlEventCallback0(myKey01)); + Assert.assertEquals(null, bt2.getAlEventCallback0(myKey02)); + Assert.assertEquals(-1, id_res[0]); + Assert.assertEquals(null, msg_res[0]); + + { + final String msgNo1 = "First message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback0Inject(myUserParam01, 0, 1, 0, msgNo1); + Assert.assertEquals( 1, id_res[0]); + Assert.assertEquals(msgNo1, msg_res[0]); + } + { + final String msgNo2 = "Second message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback0Inject(myUserParam02, 0, 2, 0, msgNo2); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback0Inject(myUserParam01, 0, 2, 0, msgNo2); + Assert.assertEquals( 2, id_res[0]); + Assert.assertEquals( msgNo2, msg_res[0]); + } + + // Switch the callback function + // The previously mapped myCallback01 (myUserParam01) gets released + // and remapped to myCallback02 + ( myUserParam01 )(key) + bt2.alEventCallback0(myCallback02, myUserParam01); + Assert.assertEquals(true, bt2.isAlEventCallback0Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02)); + { + final Set<AlEventCallback0Key> keys = bt2.getAlEventCallback0Keys(); + Assert.assertEquals(1, keys.size()); + Assert.assertEquals(true, keys.contains(myKey01)); + Assert.assertEquals(false, keys.contains(myKey02)); + } + Assert.assertEquals(myCallback02, bt2.getAlEventCallback0(myKey01)); + Assert.assertEquals(null, bt2.getAlEventCallback0(myKey02)); + + { + final String msgNo3 = "Third message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback0Inject(myUserParam02, 0, 3, 0, msgNo3); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback0Inject(myUserParam01, 0, 3, 0, msgNo3); + Assert.assertEquals( 3000, id_res[0]); + Assert.assertEquals( msgNo3, msg_res[0]); + } + + // Fake release (wrong key) + bt2.alEventCallback0(null, myUserParam02); + Assert.assertEquals(true, bt2.isAlEventCallback0Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02)); + + // Just release the callback and mapped myUserParam01 + bt2.alEventCallback0(null, myUserParam01); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02)); + Assert.assertEquals(0, bt2.getAlEventCallback0Keys().size()); + + { + final String msgNo4 = "Forth message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback0Inject(myUserParam01, 0, 4, 0, msgNo4); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback0Inject(myUserParam02, 0, 4, 0, msgNo4); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + } + } + + /** + * Test Bindingtest2 with ALEVENTPROCSOFT JavaCallback + * on alEventCallback0(..) having the 'Object userParam` and `int object` as keys. + */ + @Test + public void chapter05b() throws Exception { + final Bindingtest2 bt2 = new Bindingtest2Impl(); + + final int[] id_res = { -1 }; + final String[] msg_res = { null }; + final ALEVENTPROCSOFT myCallback01 = new ALEVENTPROCSOFT() { + @Override + public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) { + id_res[0] = object; + msg_res[0] = message; + System.err.println("chapter05.myCallback01: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+ + Integer.toHexString(System.identityHashCode(userParam))); + } + }; + final ALEVENTPROCSOFT myCallback02 = new ALEVENTPROCSOFT() { + @Override + public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) { + id_res[0] = 1000 * object; + msg_res[0] = message; + System.err.println("chapter05.myCallback02: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+ + Integer.toHexString(System.identityHashCode(userParam))); + } + }; + final Object myUserParam01 = new Object(); + final Object myUserParam02 = new Object(); + final AlEventCallback1Key myKey01 = new AlEventCallback1Key(1, myUserParam01); + final AlEventCallback1Key myKey02 = new AlEventCallback1Key(2, myUserParam02); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02)); + + bt2.alEventCallback1(1, myCallback01, myUserParam01); + Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02)); + { + final Set<AlEventCallback1Key> keys = bt2.getAlEventCallback1Keys(); + Assert.assertEquals(1, keys.size()); + Assert.assertEquals(true, keys.contains(myKey01)); + Assert.assertEquals(false, keys.contains(myKey02)); + } + Assert.assertEquals(myCallback01, bt2.getAlEventCallback1(myKey01)); + Assert.assertEquals(null, bt2.getAlEventCallback1(myKey02)); + Assert.assertEquals(-1, id_res[0]); + Assert.assertEquals(null, msg_res[0]); + + { + final String msgNo1 = "First message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback1Inject(myUserParam01, 0, 1, 0, msgNo1); + Assert.assertEquals( 1, id_res[0]); + Assert.assertEquals(msgNo1, msg_res[0]); + } + { + final String msgNo2 = "Second message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback1Inject(myUserParam02, 0, 2, 0, msgNo2); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback1Inject(myUserParam01, 0, 2, 0, msgNo2); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback1Inject(myUserParam01, 0, 1, 0, msgNo2); + Assert.assertEquals( 1, id_res[0]); + Assert.assertEquals( msgNo2, msg_res[0]); + } + + // Switch the callback function + // The previously mapped myCallback01 (1, myUserParam01) gets released + // and remapped to myCallback02 + ( 1, myUserParam01 )(key) + bt2.alEventCallback1(1, myCallback02, myUserParam01); + Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02)); + { + final Set<AlEventCallback1Key> keys = bt2.getAlEventCallback1Keys(); + Assert.assertEquals(1, keys.size()); + Assert.assertEquals(true, keys.contains(myKey01)); + Assert.assertEquals(false, keys.contains(myKey02)); + } + Assert.assertEquals(myCallback02, bt2.getAlEventCallback1(myKey01)); + Assert.assertEquals(null, bt2.getAlEventCallback1(myKey02)); + + { + final String msgNo3 = "Third message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback1Inject(myUserParam02, 0, 2, 0, msgNo3); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback1Inject(myUserParam01, 0, 2, 0, msgNo3); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback1Inject(myUserParam01, 0, 1, 0, msgNo3); + Assert.assertEquals( 1000, id_res[0]); + Assert.assertEquals( msgNo3, msg_res[0]); + } + + // Fake release (wrong key) + bt2.alEventCallback1(2, null, myUserParam02); + Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02)); + + bt2.alEventCallback1(2, null, myUserParam01); + Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02)); + + // Just release the callback and mapped myUserParam01 + bt2.alEventCallback1(1, null, myUserParam01); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey01)); + Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02)); + Assert.assertEquals(0, bt2.getAlEventCallback1Keys().size()); + + { + final String msgNo4 = "Forth message"; + id_res[0] = -1; + msg_res[0] = null; + bt2.alEventCallback1Inject(myUserParam01, 0, 4, 0, msgNo4); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + + bt2.alEventCallback1Inject(myUserParam02, 0, 4, 0, msgNo4); + Assert.assertEquals( -1, id_res[0]); + Assert.assertEquals( null, msg_res[0]); + } + } + + /** * Test Bindingtest2 with T2_CallbackFunc11 JavaCallback via MessageCallback11a() * using the default MessageCallback11aKey class. */ diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub new file mode 100644 index 0000000..28d46a6 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub @@ -0,0 +1,4 @@ + public void alEventCallback0Inject(Object userParam, int eventType, int object, int param, String message); + + public void alEventCallback1Inject(Object userParam, int eventType, int object, int param, String message); + diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub new file mode 100644 index 0000000..6643108 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub @@ -0,0 +1,46 @@ + public void alEventCallback0Inject(Object userParam, int eventType, int object, int param, String message) { + final Object userParam2; + final AlEventCallback0Data value; + synchronized( alEventCallback0Lock ) { + final AlEventCallback0Data value0 = alEventCallback0DataMap.get( new AlEventCallback0Key( userParam ) ); + if( null != value0 ) { + userParam2 = alEventCallback0UserObjIDMap.get(value0.paramID); + if( userParam != userParam2 ) { + throw new InternalError("Impl issue-1: Arg userParam "+userParam+" != "+userParam2); + } + final AlEventCallback0Key key = new AlEventCallback0Key(userParam2); + value = alEventCallback0DataMap.get( key ); + } else { + userParam2 = null; + value = null; + } + } // synchronized + if( null == value ) { + return; + } + value.func.callback(eventType, object, param, message.length(), message, userParam2); + } + + public void alEventCallback1Inject(Object userParam, int eventType, int object, int param, String message) { + final Object userParam2; + final AlEventCallback1Data value; + synchronized( alEventCallback1Lock ) { + final AlEventCallback1Data value0 = alEventCallback1DataMap.get( new AlEventCallback1Key( object, userParam ) ); + if( null != value0 ) { + userParam2 = alEventCallback1UserObjIDMap.get(value0.paramID); + if( userParam != userParam2 ) { + throw new InternalError("Impl issue-1: Arg userParam "+userParam+" != "+userParam2); + } + final AlEventCallback1Key key = new AlEventCallback1Key(object, userParam2); + value = alEventCallback1DataMap.get( key ); + } else { + userParam2 = null; + value = null; + } + } // synchronized + if( null == value ) { + return; + } + value.func.callback(eventType, object, param, message.length(), message, userParam2); + } + diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c index dafad7c..b9ad4aa 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c @@ -112,25 +112,6 @@ void InjectMessageCallback01(size_t id, const char* msg) { // // -static ALEVENTPROCSOFT alEventCallback_cb = NULL; -static void* alEventCallback_up = NULL; - -void alEventCallback(ALEVENTPROCSOFT callback, void *userParam) { - alEventCallback_cb = callback; - alEventCallback_up = userParam; -} -void alEventCallbackInject(int eventType, int object, int param, const char* msg) { - if( NULL != alEventCallback_cb ) { - fprintf(stderr, "XXX InjectMessageCallback01 func %p, user %p\n", alEventCallback_cb, alEventCallback_up); - fflush(NULL); - (*alEventCallback_cb)(eventType, object, param, strlen(msg), msg, alEventCallback_up); - } -} - -// -// -// - static const int MAX_AL_BUFFER = 5; static ALBUFFERCALLBACKTYPESOFT alBufferCallback0_callback[] = { NULL, NULL, NULL, NULL, NULL }; static void* alBufferCallback0_userptr[] = { NULL, NULL, NULL, NULL, NULL }; @@ -192,6 +173,94 @@ void alBufferCallback1Inject(int buffer, int sampledata, int numbytes) { // // +// typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam); +static const int MAX_EVENTCB_BUFFER = 5; + +static ALEVENTPROCSOFT ALEvent_callback0[] = { NULL, NULL, NULL, NULL, NULL }; +static void* ALEvent_userptr0[] = { NULL, NULL, NULL, NULL, NULL }; + +void alEventCallback0(ALEVENTPROCSOFT callback, void *userParam /* key */) { + int idx; + if( NULL == callback ) { + // try matching key + for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) { + if( ALEvent_userptr0[idx] == userParam ) { + break; + } + } + } else { + // try matching callback first + for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) { + if( ALEvent_callback0[idx] == callback ) { + break; + } + } + if( MAX_EVENTCB_BUFFER <= idx ) { + // find free slot + for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) { + if( ALEvent_callback0[idx] == NULL ) { + break; + } + } + } + } + if( idx < 0 || MAX_EVENTCB_BUFFER <= idx ) { + fprintf(stderr, "Error: alEventCallback0: idx not in range [0..%d), is %d\n", MAX_EVENTCB_BUFFER, idx); + } else { + ALEvent_callback0[idx] = callback; + ALEvent_userptr0[idx] = (ALEVENTPROCSOFT*)userParam; + fprintf(stderr, "XXX alEventCallback0 idx %d -> func %p, user %p\n", idx, callback, userParam); + } + fflush(NULL); +} + +// +// +// + +static ALEVENTPROCSOFT ALEvent_callback1[] = { NULL, NULL, NULL, NULL, NULL }; +static void* ALEvent_userptr1[] = { NULL, NULL, NULL, NULL, NULL }; + +void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */) { + // TODO: Track object key + int idx; + if( NULL == callback ) { + // try matching key + for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) { + if( ALEvent_userptr1[idx] == userParam ) { + break; + } + } + } else { + // try matching callback first + for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) { + if( ALEvent_callback1[idx] == callback ) { + break; + } + } + if( MAX_EVENTCB_BUFFER <= idx ) { + // find free slot + for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) { + if( ALEvent_callback1[idx] == NULL ) { + break; + } + } + } + } + if( idx < 0 || MAX_EVENTCB_BUFFER <= idx ) { + fprintf(stderr, "Error: alEventCallback1: idx not in range [0..%d), is %d\n", MAX_EVENTCB_BUFFER, idx); + } else { + ALEvent_callback1[idx] = callback; + ALEvent_userptr1[idx] = (ALEVENTPROCSOFT*)userParam; + fprintf(stderr, "XXX alEventCallback1 idx %d -> func %p, user %p\n", idx, callback, userParam); + } + fflush(NULL); +} + +// +// +// + static const int MAX_C11_BUFFER = 5; static T2_CallbackFunc11 MessageCallback11a_callback[] = { NULL, NULL, NULL, NULL, NULL }; @@ -228,7 +297,7 @@ void MessageCallback11aInject(size_t id, long val) { // static T2_CallbackFunc11 MessageCallback11b_callback[] = { NULL, NULL, NULL, NULL, NULL }; -static T2_Callback11UserType MessageCallback11b_userptr[]; +static T2_Callback11UserType MessageCallback11b_userptr[5]; void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data) { if( id < 0 || MAX_C11_BUFFER <= id ) { diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg index d4ea72d..3a1c7b3 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg @@ -71,33 +71,6 @@ JavaCallbackDef MessageCallback01 1 T2_CallbackFunc01 2 # # End JavaCallback -# Begin JavaCallback. -# -# typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam); -# void alEventCallback(ALEVENTPROCSOFT callback, void *userParam); -# void alEventCallbackInject(int eventType, int object, int param, const char* msg); -ArgumentIsPascalString ALEVENTPROCSOFT 3 4 -ArgumentIsString alEventCallbackInject 3 - -# Define a JavaCallback (OpenAL AL_SOFT_events) -# Set JavaCallback via function `alEventCallback` if `ALEVENTPROCSOFT` argument is non-null, otherwise removes the mapped callback and associated resources. -# -# It uses the function-pointer argument `ALEVENTPROCSOFT` as the callback function type -# and marks `ALEVENTPROCSOFT`s 6th argument (index 5) as the mandatory user-param. -# -# This callback has no keys defines, rendering it of global scope! -# The global key-less scope matches `AL_SOFT_events` semantics. -# -# Explicit maintenance methods are generated, passing the keys as paramters -# - `boolean isAlEventCallbackMapped()` queries whether `alEventCallback` is mapped globally -# - `ALEVENTPROCSOFT getAlEventCallback()` returns the global ALEVENTPROCSOFT, null if not mapped -# - `Object getAlEventCallbackUserParam()` returns the global `userParam` object, null if not mapped -# - `void releaseAlEventCallback()` releases callback data skipping toolkit API. Favor passing `null` callback ref to `alEventCallback(..)` -JavaCallbackDef alEventCallback 1 ALEVENTPROCSOFT 5 -# JavaCallbackKey alEventCallback 1 ALEVENTPROCSOFT 5 -# -# End JavaCallback - # Begin JavaCallback (OpanAL AL_SOFT_callback_buffer) # # // typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer /* key */, void *userptr, void *sampledata, int numbytes); @@ -159,6 +132,37 @@ JavaCallbackKey alBufferCallback1 1 ALBUFFERCALLBACKTYPESOFT 0 # # End JavaCallback +# Begin JavaCallback. +# +# typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam /* key */); +# +# void alEventCallback0(ALEVENTPROCSOFT callback, void *userParam /* key */); +ArgumentIsPascalString ALEVENTPROCSOFT 3 4 + +# Define a JavaCallback (OpenAL AL_SOFT_events) +# Set JavaCallback via function `alEventCallback` if `ALEVENTPROCSOFT` argument is non-null, otherwise removes the mapped callback and associated resources. +# +# It uses the function-pointer argument `ALEVENTPROCSOFT` as the callback function type +# and marks `ALEVENTPROCSOFT`s 6th argument (index 5) as the mandatory user-param. +# +# This callback uses 'Object userParam' as its key (for a context), similar to `AL_SOFT_events` context binding. +JavaCallbackDef alEventCallback0 1 ALEVENTPROCSOFT 5 +JavaCallbackKey alEventCallback0 1 ALEVENTPROCSOFT 5 +# +# End JavaCallback + +# Begin JavaCallback. +# +# void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */); +JavaCallbackDef alEventCallback1 2 ALEVENTPROCSOFT 5 +JavaCallbackKey alEventCallback1 0 2 ALEVENTPROCSOFT 1 5 + +# +# End JavaCallback + +IncludeAs CustomJavaCode Bindingtest2 test2-CustomJavaIfCode.java.stub +IncludeAs CustomJavaCode Bindingtest2Impl test2-CustomJavaImplCode.java.stub + # Begin JavaCallback # # typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam); diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h index dea6d72..ddd8c8a 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h @@ -67,14 +67,6 @@ void MessageCallback01(T2_CallbackFunc01 cbFunc, void* usrParam); void InjectMessageCallback01(size_t id, const char* msg); // -// ALEVENTPROCSOFT (similar to OpenAL's AL_SOFT_events) -// -typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam); - -void alEventCallback(ALEVENTPROCSOFT callback, void *userParam); -void alEventCallbackInject(int eventType, int object, int param, const char* msg); - -// // ALBUFFERCALLBACKTYPESOFT (similar to OpenAL's AL_SOFT_callback_buffer) // // typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer, void *userptr, void *sampledata, int numbytes); @@ -89,6 +81,15 @@ void alBufferCallback1(void* user_ptr, int buffer_key /* key */, int format, int void alBufferCallback1Inject(int buffer, int sampledata, int numbytes); // +// ALEVENTPROCSOFT (similar to OpenAL's AL_SOFT_events) +// +typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam /* key */); + +void alEventCallback0(ALEVENTPROCSOFT callback, void *userParam /* key */); + +void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */); + +// // T2_CallbackFunc11[ab] // typedef struct { |