Home | History | Annotate | Download | only in gles11
      1 #include "jni.h"
      2 #include "JNIHelp.h"
      3 #include <android_runtime/AndroidRuntime.h>
      4 #include <utils/misc.h>
      5 #include <assert.h>
      6 
      7 static int initialized = 0;
      8 
      9 static jclass nioAccessClass;
     10 static jclass bufferClass;
     11 static jmethodID getBasePointerID;
     12 static jmethodID getBaseArrayID;
     13 static jmethodID getBaseArrayOffsetID;
     14 static jfieldID positionID;
     15 static jfieldID limitID;
     16 static jfieldID elementSizeShiftID;
     17 
     18 
     19 /* special calls implemented in Android's GLES wrapper used to more
     20  * efficiently bound-check passed arrays */
     21 extern "C" {
     22 #ifdef GL_VERSION_ES_CM_1_1
     23 GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
     24         const GLvoid *ptr, GLsizei count);
     25 GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
     26         const GLvoid *pointer, GLsizei count);
     27 GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
     28         GLsizei stride, const GLvoid *pointer, GLsizei count);
     29 GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
     30         GLsizei stride, const GLvoid *pointer, GLsizei count);
     31 GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
     32         GLsizei stride, const GLvoid *pointer, GLsizei count);
     33 GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
     34         GLsizei stride, const GLvoid *pointer, GLsizei count);
     35 GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
     36         GLsizei stride, const GLvoid *pointer, GLsizei count);
     37 #endif
     38 #ifdef GL_ES_VERSION_2_0
     39 static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
     40         GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) {
     41     glVertexAttribPointer(indx, size, type, normalized, stride, pointer);
     42 }
     43 #endif
     44 #ifdef GL_ES_VERSION_3_0
     45 static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type,
     46         GLsizei stride, const GLvoid *pointer, GLsizei count) {
     47     glVertexAttribIPointer(indx, size, type, stride, pointer);
     48 }
     49 #endif
     50 }
     51 
     52 /* Cache method IDs each time the class is loaded. */
     53 
     54 static void
     55 nativeClassInit(JNIEnv *_env, jclass glImplClass)
     56 {
     57     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     58     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
     59 
     60     jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
     61     bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
     62 
     63     getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
     64             "getBasePointer", "(Ljava/nio/Buffer;)J");
     65     getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
     66             "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
     67     getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
     68             "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
     69 
     70     positionID = _env->GetFieldID(bufferClass, "position", "I");
     71     limitID = _env->GetFieldID(bufferClass, "limit", "I");
     72     elementSizeShiftID =
     73         _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
     74 }
     75 
     76 static void *
     77 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
     78 {
     79     jint position;
     80     jint limit;
     81     jint elementSizeShift;
     82     jlong pointer;
     83 
     84     position = _env->GetIntField(buffer, positionID);
     85     limit = _env->GetIntField(buffer, limitID);
     86     elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
     87     *remaining = (limit - position) << elementSizeShift;
     88     pointer = _env->CallStaticLongMethod(nioAccessClass,
     89             getBasePointerID, buffer);
     90     if (pointer != 0L) {
     91         *array = NULL;
     92         return (void *) (jint) pointer;
     93     }
     94 
     95     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
     96             getBaseArrayID, buffer);
     97     *offset = _env->CallStaticIntMethod(nioAccessClass,
     98             getBaseArrayOffsetID, buffer);
     99 
    100     return NULL;
    101 }
    102 
    103 static void
    104 releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
    105 {
    106     _env->ReleasePrimitiveArrayCritical(array, data,
    107                        commit ? 0 : JNI_ABORT);
    108 }
    109 
    110 static void *
    111 getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
    112     char* buf = (char*) _env->GetDirectBufferAddress(buffer);
    113     if (buf) {
    114         jint position = _env->GetIntField(buffer, positionID);
    115         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
    116         buf += position << elementSizeShift;
    117     } else {
    118         jniThrowException(_env, "java/lang/IllegalArgumentException",
    119                           "Must use a native order direct Buffer");
    120     }
    121     return (void*) buf;
    122 }
    123 
    124 // --------------------------------------------------------------------------
    125 
    126 /*
    127  * returns the number of values glGet returns for a given pname.
    128  *
    129  * The code below is written such that pnames requiring only one values
    130  * are the default (and are not explicitely tested for). This makes the
    131  * checking code much shorter/readable/efficient.
    132  *
    133  * This means that unknown pnames (e.g.: extensions) will default to 1. If
    134  * that unknown pname needs more than 1 value, then the validation check
    135  * is incomplete and the app may crash if it passed the wrong number params.
    136  */
    137 static int getNeededCount(GLint pname) {
    138     int needed = 1;
    139 #ifdef GL_ES_VERSION_2_0
    140     // GLES 2.x pnames
    141     switch (pname) {
    142         case GL_ALIASED_LINE_WIDTH_RANGE:
    143         case GL_ALIASED_POINT_SIZE_RANGE:
    144             needed = 2;
    145             break;
    146 
    147         case GL_BLEND_COLOR:
    148         case GL_COLOR_CLEAR_VALUE:
    149         case GL_COLOR_WRITEMASK:
    150         case GL_SCISSOR_BOX:
    151         case GL_VIEWPORT:
    152             needed = 4;
    153             break;
    154 
    155         case GL_COMPRESSED_TEXTURE_FORMATS:
    156             glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
    157             break;
    158 
    159         case GL_SHADER_BINARY_FORMATS:
    160             glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed);
    161             break;
    162     }
    163 #endif
    164 
    165 #ifdef GL_VERSION_ES_CM_1_1
    166     // GLES 1.x pnames
    167     switch (pname) {
    168         case GL_ALIASED_LINE_WIDTH_RANGE:
    169         case GL_ALIASED_POINT_SIZE_RANGE:
    170         case GL_DEPTH_RANGE:
    171         case GL_SMOOTH_LINE_WIDTH_RANGE:
    172         case GL_SMOOTH_POINT_SIZE_RANGE:
    173             needed = 2;
    174             break;
    175 
    176         case GL_CURRENT_NORMAL:
    177         case GL_POINT_DISTANCE_ATTENUATION:
    178             needed = 3;
    179             break;
    180 
    181         case GL_COLOR_CLEAR_VALUE:
    182         case GL_COLOR_WRITEMASK:
    183         case GL_CURRENT_COLOR:
    184         case GL_CURRENT_TEXTURE_COORDS:
    185         case GL_FOG_COLOR:
    186         case GL_LIGHT_MODEL_AMBIENT:
    187         case GL_SCISSOR_BOX:
    188         case GL_VIEWPORT:
    189             needed = 4;
    190             break;
    191 
    192         case GL_MODELVIEW_MATRIX:
    193         case GL_PROJECTION_MATRIX:
    194         case GL_TEXTURE_MATRIX:
    195             needed = 16;
    196             break;
    197 
    198         case GL_COMPRESSED_TEXTURE_FORMATS:
    199             glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
    200             break;
    201     }
    202 #endif
    203     return needed;
    204 }
    205 
    206 template <typename JTYPEARRAY, typename CTYPE, void GET(GLenum, CTYPE*)>
    207 static void
    208 get
    209   (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
    210     jint _exception = 0;
    211     const char * _exceptionType;
    212     const char * _exceptionMessage;
    213     CTYPE *params_base = (CTYPE *) 0;
    214     jint _remaining;
    215     CTYPE *params = (CTYPE *) 0;
    216     int _needed = 0;
    217 
    218     if (!params_ref) {
    219         _exception = 1;
    220         _exceptionType = "java/lang/IllegalArgumentException";
    221         _exceptionMessage = "params == null";
    222         goto exit;
    223     }
    224     if (offset < 0) {
    225         _exception = 1;
    226         _exceptionType = "java/lang/IllegalArgumentException";
    227         _exceptionMessage = "offset < 0";
    228         goto exit;
    229     }
    230     _remaining = _env->GetArrayLength(params_ref) - offset;
    231     _needed = getNeededCount(pname);
    232     // if we didn't find this pname, we just assume the user passed
    233     // an array of the right size -- this might happen with extensions
    234     // or if we forget an enum here.
    235     if (_remaining < _needed) {
    236         _exception = 1;
    237         _exceptionType = "java/lang/IllegalArgumentException";
    238         _exceptionMessage = "length - offset < needed";
    239         goto exit;
    240     }
    241     params_base = (CTYPE *)
    242         _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
    243     params = params_base + offset;
    244 
    245     GET(
    246         (GLenum)pname,
    247         (CTYPE *)params
    248     );
    249 
    250 exit:
    251     if (params_base) {
    252         _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
    253             _exception ? JNI_ABORT: 0);
    254     }
    255     if (_exception) {
    256         jniThrowException(_env, _exceptionType, _exceptionMessage);
    257     }
    258 }
    259 
    260 
    261 template <typename CTYPE, void GET(GLenum, CTYPE*)>
    262 static void
    263 getarray
    264   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
    265     jint _exception = 0;
    266     const char * _exceptionType;
    267     const char * _exceptionMessage;
    268     jarray _array = (jarray) 0;
    269     jint _bufferOffset = (jint) 0;
    270     jint _remaining;
    271     CTYPE *params = (CTYPE *) 0;
    272     int _needed = 0;
    273 
    274     params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
    275     _remaining /= sizeof(CTYPE);    // convert from bytes to item count
    276     _needed = getNeededCount(pname);
    277     // if we didn't find this pname, we just assume the user passed
    278     // an array of the right size -- this might happen with extensions
    279     // or if we forget an enum here.
    280     if (_needed>0 && _remaining < _needed) {
    281         _exception = 1;
    282         _exceptionType = "java/lang/IllegalArgumentException";
    283         _exceptionMessage = "remaining() < needed";
    284         goto exit;
    285     }
    286     if (params == NULL) {
    287         char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
    288         params = (CTYPE *) (_paramsBase + _bufferOffset);
    289     }
    290     GET(
    291         (GLenum)pname,
    292         (CTYPE *)params
    293     );
    294 
    295 exit:
    296     if (_array) {
    297         releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
    298     }
    299     if (_exception) {
    300         jniThrowException(_env, _exceptionType, _exceptionMessage);
    301     }
    302 }
    303 
    304 // --------------------------------------------------------------------------
    305