From 0192562ce71078ce91cf02458ee92bc4603dc8ad Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Sun, 26 Feb 2006 18:48:26 +0000 Subject: Added XGetVisualInfo and glXChooseFBConfig examples from JOGL. Intended initial set of configuration file examples is now complete. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/gluegen/trunk@19 a78bb65f-1512-4460-ba86-f6dc96a7bf27 --- doc/manual/example6/function.cfg | 25 ++++ doc/manual/example6/function.h | 23 +++ doc/manual/example6/gen.sh | 17 +++ doc/manual/example7/function.cfg | 15 ++ doc/manual/example7/function.h | 5 + doc/manual/example7/gen.sh | 17 +++ doc/manual/index.html | 293 ++++++++++++++++++++++++++++++++++++++- 7 files changed, 388 insertions(+), 7 deletions(-) create mode 100644 doc/manual/example6/function.cfg create mode 100644 doc/manual/example6/function.h create mode 100644 doc/manual/example6/gen.sh create mode 100644 doc/manual/example7/function.cfg create mode 100644 doc/manual/example7/function.h create mode 100644 doc/manual/example7/gen.sh diff --git a/doc/manual/example6/function.cfg b/doc/manual/example6/function.cfg new file mode 100644 index 0000000..c94e856 --- /dev/null +++ b/doc/manual/example6/function.cfg @@ -0,0 +1,25 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native + +# Get returned array's capacity from XGetVisualInfo to be correct +TemporaryCVariableDeclaration XGetVisualInfo int count; +TemporaryCVariableAssignment XGetVisualInfo count = _ptr3[0]; +ReturnValueCapacity XGetVisualInfo count * sizeof(XVisualInfo) + +# Helper routine to make the ReturnedArrayLength expression below work correctly +CustomJavaCode TestFunction private static int getFirstElement(IntBuffer buf) { return buf.get(buf.position()); } +CustomJavaCode TestFunction private static int getFirstElement(int[] arr, int offset) { return arr[offset]; } +ReturnedArrayLength XGetVisualInfo getFirstElement({3}) + +# We don't need the Display and Visual data structures to be +# explicitly exposed +Opaque long Display * +Opaque long Visual * +# Ignore the empty Display and Visual data structures (though made +# opaque, the references from XVisualInfo and elsewhere are still +# traversed) +Ignore Display +Ignore Visual diff --git a/doc/manual/example6/function.h b/doc/manual/example6/function.h new file mode 100644 index 0000000..0517471 --- /dev/null +++ b/doc/manual/example6/function.h @@ -0,0 +1,23 @@ +typedef struct {} Display; +typedef struct {} Visual; +typedef unsigned long VisualID; + +typedef struct { + Visual *visual; + VisualID visualid; + int screen; + int depth; + int c_class; /* C++ */ + unsigned long red_mask; + unsigned long green_mask; + unsigned long blue_mask; + int colormap_size; + int bits_per_rgb; +} XVisualInfo; + +XVisualInfo *XGetVisualInfo( + Display* /* display */, + long /* vinfo_mask */, + XVisualInfo* /* vinfo_template */, + int* /* nitems_return */ +); diff --git a/doc/manual/example6/gen.sh b/doc/manual/example6/gen.sh new file mode 100644 index 0000000..6fb971e --- /dev/null +++ b/doc/manual/example6/gen.sh @@ -0,0 +1,17 @@ +#!/bin/ksh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/example7/function.cfg b/doc/manual/example7/function.cfg new file mode 100644 index 0000000..2ac8560 --- /dev/null +++ b/doc/manual/example7/function.cfg @@ -0,0 +1,15 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native + +TemporaryCVariableDeclaration glXChooseFBConfig int count; +TemporaryCVariableAssignment glXChooseFBConfig count = _ptr3[0]; +ReturnValueLength glXChooseFBConfig count + +# We don't need the Display data structure to be explicitly exposed +Opaque long Display * +# Ignore the empty Display data structure (though made opaque, the +# reference from glxChooseFBConfig is still traversed) +Ignore Display diff --git a/doc/manual/example7/function.h b/doc/manual/example7/function.h new file mode 100644 index 0000000..2882d2a --- /dev/null +++ b/doc/manual/example7/function.h @@ -0,0 +1,5 @@ +typedef struct {} Display; +typedef struct __GLXFBConfigRec *GLXFBConfig; + +GLXFBConfig *glXChooseFBConfig( Display *dpy, int screen, + const int *attribList, int *nitems ); diff --git a/doc/manual/example7/gen.sh b/doc/manual/example7/gen.sh new file mode 100644 index 0000000..6fb971e --- /dev/null +++ b/doc/manual/example7/gen.sh @@ -0,0 +1,17 @@ +#!/bin/ksh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/index.html b/doc/manual/index.html index e2e0fbc..ec1ff3a 100755 --- a/doc/manual/index.html +++ b/doc/manual/index.html @@ -44,13 +44,8 @@ Chapter 3 - Configuration File Examples
  • String handling
  • Memory allocation
  • Ingoing and outgoing structs - - -TO DO: - -

    Chapter 1 - Introduction

    @@ -1960,16 +1955,300 @@ is no longer reachable, as it is backed by a direct New I/O ByteBuffer. The fields of the struct are exposed as methods which supply both getters and setters.

    +

    Returned arrays of structs

    + +Files: + + +

    This example, taken from JOGL's X11 binding, illustrates how to +return an array of structs from C to Java. The +XGetVisualInfo function from the X library has the +following signature:

    + +
    +  XVisualInfo *XGetVisualInfo(
    +      Display*     display,
    +      long         vinfo_mask,
    +      XVisualInfo* vinfo_template,
    +      int*         nitems_return
    +  );
    +
    + +

    Note that the XVisualInfo data structure itself +contains many elements, including a pointer to the current visual. We +use the following trick in the header file to cause GlueGen to treat +the Display* in the above signature as well as the +Visual* in the XVisualInfo as opaque +pointers:

    + +
    +  typedef struct {}     Display;
    +  typedef struct {}     Visual;
    +  typedef unsigned long VisualID;
    +  
    +  typedef struct {
    +    Visual *visual;
    +    VisualID visualid;
    +    int screen;
    +    int depth;
    +    int c_class; /* C++ */
    +    unsigned long red_mask;
    +    unsigned long green_mask;
    +    unsigned long blue_mask;
    +    int colormap_size;
    +    int bits_per_rgb;
    +  } XVisualInfo;
    +
    + +

    XGetVisualInfo returns all of the available pixel +formats in the form of XVisualInfos which match a given +template. display is the current connection to the X +server. vinfo_mask indicates which fields from the +template to match against. vinfo_template is a partially +filled-in XVisualInfo specifying the characteristics to +match. nitems_return is a pointer to an integer +indicating how many XVisualInfos were returned. The +return value, rather than being a pointer to a single +XVisualInfo, is a pointer to the start of an array of +XVisualInfo data structures.

    + +

    There are two basic steps to being able to return this array +properly to Java using GlueGen. The first is creating a direct +ByteBuffer of the appropriate size in the autogenerated JNI code. The +second is slicing up this ByteBuffer appropriately in order to return +an XVisualInfo[] at the Java level.

    + +

    In the autogenerated JNI code, after the call to +XGetVisualInfo is made, the outgoing +nitems_return value points to the number of elements in +the returned array, which indicates the size of the direct ByteBuffer +which would need to wrap these elements. However, if we look at the +implementation of one of the generated glue code variants for this +method (specifically, the one taking an int[] as the +third argument), we can see a problem in trying to access this value +in the C code:

    + +
    +JNIEXPORT jobject JNICALL 
    +Java_testfunction_TestFunction_XGetVisualInfo1__Ljava_nio_ByteBuffer_2JLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(
    +  JNIEnv *env, jclass _unused, jobject arg0, jlong arg1, jobject arg2, jobject arg3, jint arg3_byte_offset) {
    +  ...
    +  int * _ptr3 = NULL;
    +  ...
    +  if (arg3 != NULL) {
    +    _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset);
    +  }
    +  _res = XGetVisualInfo((Display *) _ptr0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3);
    +  if (arg3 != NULL) {
    +    (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0);
    +  }
    +  if (_res == NULL) return NULL;
    +  return (*env)->NewDirectByteBuffer(env, _res,  ??? What to put here ???);
    +}
    +
    + +

    Note that at the point of the statement "What to put here?" the +pointer to the storage of the int[], _ptr3, +has already been released via +ReleasePrimitiveArrayCritical. This means that it may not +be referenced at the point needed in the code.

    + +

    To solve this problem we use the TemporaryCVariableDeclaration +and TemporaryCVariableAssignment +directives. We want to declare a persistent integer variable down in +the C code and assign the returned array length to that variable +before the primitive array is released. While in order to do this we +unfortunately need to know something about the structure of the +autogenerated JNI code, at least we don't have to hand-edit it +afterward. We add the following directives to the configuration file:

    + +
    +  # Get returned array's capacity from XGetVisualInfo to be correct
    +  TemporaryCVariableDeclaration XGetVisualInfo   int count;
    +  TemporaryCVariableAssignment  XGetVisualInfo   count = _ptr3[0];
    +
    + +

    Now in the autogenerated JNI code the variable "count" will +contain the number of elements in the returned array. We can then +reference this variable in a ReturnValueCapacity directive:

    + +
    +  ReturnValueCapacity XGetVisualInfo   count * sizeof(XVisualInfo)
    +
    + +

    At this point the XGetVisualInfo binding will return +a Java-side XVisualInfo object whose backing ByteBuffer +is the correct size. We now have to inform GlueGen that the underlying +ByteBuffer represents not a single XGetVisualInfo struct, +but an array of them, using the ReturnedArrayLength directive. This +conversion is performed on the Java side of the autogenerated code. +Here, the first element of either the passed IntBuffer or +int[] contains the number of elements in the returned +array. (Alternatively, we could examine the length of the ByteBuffer +returned from C to Java and divide by +XVisualInfo.size().) Because there are two overloadings +produced by GlueGen for this method, if we reference the +nitems_return argument in a ReturnedArrayLength directive, we need +to handle not only the differing data types properly +(IntBuffer vs. int[]), but also the fact +that both the integer array and its offset value are substituted for +any reference to the fourth argument.

    + +

    To solve this problem, we define a pair of private helper +functions whose purpose is to handle this overloading.

    + +
    +  CustomJavaCode TestFunction  private static int getFirstElement(IntBuffer buf) {
    +  CustomJavaCode TestFunction    return buf.get(buf.position());
    +  CustomJavaCode TestFunction  }
    +  CustomJavaCode TestFunction  private static int getFirstElement(int[] arr,
    +  CustomJavaCode TestFunction                                     int offset) {
    +  CustomJavaCode TestFunction    return arr[offset];
    +  CustomJavaCode TestFunction  }
    +
    + +

    Now we can simply write for the returned array length:

    + +
    +  ReturnedArrayLength XGetVisualInfo  getFirstElement({3})
    +
    + +

    That's all that is necessary. GlueGen will then produce the +following Java-side overloadings for this function:

    + +
    +  public static XVisualInfo[] XGetVisualInfo(Display arg0,
    +                                             long arg1,
    +                                             XVisualInfo arg2,
    +                                             java.nio.IntBuffer arg3);
    +  public static XVisualInfo[] XGetVisualInfo(Display arg0,
    +                                             long arg1,
    +                                             XVisualInfo arg2,
    +                                             int[] arg3, int arg3_offset);
    +
    + +

    As it happens, we don't really need the Display and Visual data +structures to be produced; they can be treated as longs +on the Java side. Therefore we can add the following directives to the +configuration file:

    + +
    +  # We don't need the Display and Visual data structures to be
    +  # explicitly exposed
    +  Opaque long Display *
    +  Opaque long Visual *
    +  # Ignore the empty Display and Visual data structures (though made
    +  # opaque, the references from XVisualInfo and elsewhere are still
    +  # traversed)
    +  Ignore Display
    +  Ignore Visual
    +
    + +

    The final generated Java API is the following:

    +
    +  public static XVisualInfo[] XGetVisualInfo(long arg0,
    +                                             long arg1,
    +                                             XVisualInfo arg2,
    +                                             java.nio.IntBuffer arg3);
    +  public static XVisualInfo[] XGetVisualInfo(long arg0,
    +                                             long arg1,
    +                                             XVisualInfo arg2,
    +                                             int[] arg3, int arg3_offset);
    +
    +

    Returned arrays of pointers

    +Files: + +

    As with the example above, this +example is taken from JOGL's X11 binding. Here we show how to expose +to Java a C routine returning an array of pointers to a data +structure.

    +

    The declaration of the function we are binding is as follows:

    +
    +  typedef struct __GLXFBConfigRec *GLXFBConfig;
     
    +  GLXFBConfig *glXChooseFBConfig( Display *dpy, int screen,
    +                                  const int *attribList, int *nitems );
    +
    +

    This function is used during allocation of a hardware-accelerated +off-screen surface ("pbuffer") on X11 platforms; its exact meaning is +not important. The semantics of the arguments and return value are as +follows. As in the previous example, it +accepts a connection to the current X display as one argument. The +screen of this display is the second argument. The +attribList is a zero-terminated list of integer +attributes; because it is zero-terminated, the length of this list is +not passed to the function. As in the previous example, the +nitems argument points to an integer into which the +number of returned GLXFBConfig objects is placed. The +return value is an array of GLXFBConfig objects.

    + +

    Because the GLXFBConfig data type is typedefed as a +pointer to an opaque (undefined) struct, the construct +GLXFBConfig* is implicitly a "pointer-to-pointer" type. +GlueGen automatically assumes this is convertible to a Java-side array +of accessors to structs. The only configuration necessary is to tell +GlueGen the length of this array.

    + +

    As in the previous example, we use the TemporaryCVariableDeclaration +and TemporaryCVariableAssignment +directives to capture the length of the returned array:

    +TemporaryCVariableDeclaration glXChooseFBConfig int count; +TemporaryCVariableAssignment glXChooseFBConfig count = _ptr3[0]; + +

    The structure of the generated glue code for the return value is +subtly different than in the previous example. The question in this +case is not whether the return value is a pointer to a single object +vs. a pointer to an array of objects; it is what the length of the +returned array is, since we already know that the return type is +pointer-to-pointer and is therefore an array. We use the ReturnValueLength directive for this +case:

    + +
    +  ReturnValueLength glXChooseFBConfig   count
    +
    + +We add similar Opaque directives to the previous example to yield the +resulting Java bindings for this function: + +
    +  public static GLXFBConfig[] glXChooseFBConfig(long dpy,
    +                                                int screen,
    +                                                java.nio.IntBuffer attribList,
    +                                                java.nio.IntBuffer nitems);
    +  public static GLXFBConfig[] glXChooseFBConfig(long dpy,
    +                                                int screen,
    +                                                int[] attribList, int attribList_offset,
    +                                                int[] nitems, int nitems_offset);
    +
    +Note that because the GLXFBConfig data type is returned as an element +of an array, we can not use the Opaque directive to erase this data +type to long as we did with the Display data +type. -- cgit v1.2.3