Home | History | Annotate | Download | only in gles11
      1 #include <jni.h>
      2 #include <nativehelper/JNIHelp.h>
      3 #include <android_runtime/AndroidRuntime.h>
      4 #include <utils/misc.h>
      5 #include <assert.h>
      6 
      7 
      8 /* special calls implemented in Android's GLES wrapper used to more
      9  * efficiently bound-check passed arrays */
     10 extern "C" {
     11 #ifdef GL_VERSION_ES_CM_1_1
     12 GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
     13         const GLvoid *ptr, GLsizei count);
     14 GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
     15         const GLvoid *pointer, GLsizei count);
     16 GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
     17         GLsizei stride, const GLvoid *pointer, GLsizei count);
     18 GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
     19         GLsizei stride, const GLvoid *pointer, GLsizei count);
     20 GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
     21         GLsizei stride, const GLvoid *pointer, GLsizei count);
     22 GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
     23         GLsizei stride, const GLvoid *pointer, GLsizei count);
     24 GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
     25         GLsizei stride, const GLvoid *pointer, GLsizei count);
     26 #endif
     27 #ifdef GL_ES_VERSION_2_0
     28 static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
     29         GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) {
     30     glVertexAttribPointer(indx, size, type, normalized, stride, pointer);
     31 }
     32 #endif
     33 #ifdef GL_ES_VERSION_3_0
     34 static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type,
     35         GLsizei stride, const GLvoid *pointer, GLsizei count) {
     36     glVertexAttribIPointer(indx, size, type, stride, pointer);
     37 }
     38 #endif
     39 }
     40 
     41 static void
     42 nativeClassInit(JNIEnv *_env, jclass glImplClass)
     43 {
     44 }
     45 
     46 static void *
     47 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
     48 {
     49     jint position;
     50     jint limit;
     51     jint elementSizeShift;
     52     jlong pointer;
     53 
     54     pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift);
     55     *remaining = (limit - position) << elementSizeShift;
     56     if (pointer != 0L) {
     57         *array = nullptr;
     58         pointer += position << elementSizeShift;
     59         return reinterpret_cast<void*>(pointer);
     60     }
     61 
     62     *array = jniGetNioBufferBaseArray(_env, buffer);
     63     *offset = jniGetNioBufferBaseArrayOffset(_env, buffer);
     64     return nullptr;
     65 }
     66 
     67 class ByteArrayGetter {
     68 public:
     69     static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
     70         return _env->GetByteArrayElements(array, is_copy);
     71     }
     72 };
     73 class BooleanArrayGetter {
     74 public:
     75     static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
     76         return _env->GetBooleanArrayElements(array, is_copy);
     77     }
     78 };
     79 class CharArrayGetter {
     80 public:
     81     static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
     82         return _env->GetCharArrayElements(array, is_copy);
     83     }
     84 };
     85 class ShortArrayGetter {
     86 public:
     87     static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
     88         return _env->GetShortArrayElements(array, is_copy);
     89     }
     90 };
     91 class IntArrayGetter {
     92 public:
     93     static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
     94         return _env->GetIntArrayElements(array, is_copy);
     95     }
     96 };
     97 class LongArrayGetter {
     98 public:
     99     static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
    100         return _env->GetLongArrayElements(array, is_copy);
    101     }
    102 };
    103 class FloatArrayGetter {
    104 public:
    105     static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
    106         return _env->GetFloatArrayElements(array, is_copy);
    107     }
    108 };
    109 class DoubleArrayGetter {
    110 public:
    111     static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
    112         return _env->GetDoubleArrayElements(array, is_copy);
    113     }
    114 };
    115 
    116 template<typename JTYPEARRAY, typename ARRAYGETTER>
    117 static void*
    118 getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) {
    119     return ARRAYGETTER::Get(_env, array, is_copy);
    120 }
    121 
    122 class ByteArrayReleaser {
    123 public:
    124     static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) {
    125         _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT);
    126     }
    127 };
    128 class BooleanArrayReleaser {
    129 public:
    130     static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) {
    131         _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT);
    132     }
    133 };
    134 class CharArrayReleaser {
    135 public:
    136     static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) {
    137         _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT);
    138     }
    139 };
    140 class ShortArrayReleaser {
    141 public:
    142     static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) {
    143         _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT);
    144     }
    145 };
    146 class IntArrayReleaser {
    147 public:
    148     static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) {
    149         _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT);
    150     }
    151 };
    152 class LongArrayReleaser {
    153 public:
    154     static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) {
    155         _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT);
    156     }
    157 };
    158 class FloatArrayReleaser {
    159 public:
    160     static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) {
    161         _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT);
    162     }
    163 };
    164 class DoubleArrayReleaser {
    165 public:
    166     static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) {
    167         _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT);
    168     }
    169 };
    170 
    171 template<typename JTYPEARRAY, typename NTYPEARRAY, typename ARRAYRELEASER>
    172 static void
    173 releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) {
    174     ARRAYRELEASER::Release(_env, array, data, commit);
    175 }
    176 
    177 static void
    178 releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
    179 {
    180     _env->ReleasePrimitiveArrayCritical(array, data,
    181                        commit ? 0 : JNI_ABORT);
    182 }
    183 
    184 static void *
    185 getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
    186     jint position;
    187     jint limit;
    188     jint elementSizeShift;
    189     jlong pointer;
    190     pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift);
    191     if (pointer == 0) {
    192         jniThrowException(_env, "java/lang/IllegalArgumentException",
    193                           "Must use a native order direct Buffer");
    194         return nullptr;
    195     }
    196     pointer += position << elementSizeShift;
    197     return reinterpret_cast<void*>(pointer);
    198 }
    199 
    200 // --------------------------------------------------------------------------
    201 
    202 /*
    203  * returns the number of values glGet returns for a given pname.
    204  *
    205  * The code below is written such that pnames requiring only one values
    206  * are the default (and are not explicitely tested for). This makes the
    207  * checking code much shorter/readable/efficient.
    208  *
    209  * This means that unknown pnames (e.g.: extensions) will default to 1. If
    210  * that unknown pname needs more than 1 value, then the validation check
    211  * is incomplete and the app may crash if it passed the wrong number params.
    212  */
    213 static int getNeededCount(GLint pname) {
    214     int needed = 1;
    215 #ifdef GL_ES_VERSION_3_0
    216     // GLES 3.x pnames
    217     switch (pname) {
    218         case GL_MAX_VIEWPORT_DIMS:
    219             needed = 2;
    220             break;
    221 
    222         case GL_PROGRAM_BINARY_FORMATS:
    223             glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &needed);
    224             break;
    225     }
    226 #endif
    227 
    228 #ifdef GL_ES_VERSION_2_0
    229     // GLES 2.x pnames
    230     switch (pname) {
    231         case GL_ALIASED_LINE_WIDTH_RANGE:
    232         case GL_ALIASED_POINT_SIZE_RANGE:
    233             needed = 2;
    234             break;
    235 
    236         case GL_BLEND_COLOR:
    237         case GL_COLOR_CLEAR_VALUE:
    238         case GL_COLOR_WRITEMASK:
    239         case GL_SCISSOR_BOX:
    240         case GL_VIEWPORT:
    241             needed = 4;
    242             break;
    243 
    244         case GL_COMPRESSED_TEXTURE_FORMATS:
    245             glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
    246             break;
    247 
    248         case GL_SHADER_BINARY_FORMATS:
    249             glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed);
    250             break;
    251     }
    252 #endif
    253 
    254 #ifdef GL_VERSION_ES_CM_1_1
    255     // GLES 1.x pnames
    256     switch (pname) {
    257         case GL_ALIASED_LINE_WIDTH_RANGE:
    258         case GL_ALIASED_POINT_SIZE_RANGE:
    259         case GL_DEPTH_RANGE:
    260         case GL_SMOOTH_LINE_WIDTH_RANGE:
    261         case GL_SMOOTH_POINT_SIZE_RANGE:
    262             needed = 2;
    263             break;
    264 
    265         case GL_CURRENT_NORMAL:
    266         case GL_POINT_DISTANCE_ATTENUATION:
    267             needed = 3;
    268             break;
    269 
    270         case GL_COLOR_CLEAR_VALUE:
    271         case GL_COLOR_WRITEMASK:
    272         case GL_CURRENT_COLOR:
    273         case GL_CURRENT_TEXTURE_COORDS:
    274         case GL_FOG_COLOR:
    275         case GL_LIGHT_MODEL_AMBIENT:
    276         case GL_SCISSOR_BOX:
    277         case GL_VIEWPORT:
    278             needed = 4;
    279             break;
    280 
    281         case GL_MODELVIEW_MATRIX:
    282         case GL_PROJECTION_MATRIX:
    283         case GL_TEXTURE_MATRIX:
    284             needed = 16;
    285             break;
    286 
    287         case GL_COMPRESSED_TEXTURE_FORMATS:
    288             glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
    289             break;
    290     }
    291 #endif
    292     return needed;
    293 }
    294 
    295 template <typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
    296           typename ARRAYRELEASER, typename CTYPE, void GET(GLenum, CTYPE*)>
    297 static void
    298 get
    299   (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
    300     jint _exception = 0;
    301     const char * _exceptionType;
    302     const char * _exceptionMessage;
    303     CTYPE *params_base = (CTYPE *) 0;
    304     jint _remaining;
    305     CTYPE *params = (CTYPE *) 0;
    306     int _needed = 0;
    307 
    308     if (!params_ref) {
    309         _exception = 1;
    310         _exceptionType = "java/lang/IllegalArgumentException";
    311         _exceptionMessage = "params == null";
    312         goto exit;
    313     }
    314     if (offset < 0) {
    315         _exception = 1;
    316         _exceptionType = "java/lang/IllegalArgumentException";
    317         _exceptionMessage = "offset < 0";
    318         goto exit;
    319     }
    320     _remaining = _env->GetArrayLength(params_ref) - offset;
    321     _needed = getNeededCount(pname);
    322     // if we didn't find this pname, we just assume the user passed
    323     // an array of the right size -- this might happen with extensions
    324     // or if we forget an enum here.
    325     if (_remaining < _needed) {
    326         _exception = 1;
    327         _exceptionType = "java/lang/IllegalArgumentException";
    328         _exceptionMessage = "length - offset < needed";
    329         goto exit;
    330     }
    331     params_base = (CTYPE *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
    332         _env, params_ref, (jboolean *)0);
    333     params = params_base + offset;
    334 
    335     GET(
    336         (GLenum)pname,
    337         (CTYPE *)params
    338     );
    339 
    340 exit:
    341     if (params_base) {
    342         releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
    343             _env, params_ref, params_base, !_exception);
    344     }
    345     if (_exception) {
    346         jniThrowException(_env, _exceptionType, _exceptionMessage);
    347     }
    348 }
    349 
    350 
    351 template <typename CTYPE, typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
    352           typename ARRAYRELEASER, void GET(GLenum, CTYPE*)>
    353 static void
    354 getarray
    355   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
    356     jint _exception = 0;
    357     const char * _exceptionType;
    358     const char * _exceptionMessage;
    359     JTYPEARRAY _array = (JTYPEARRAY) 0;
    360     jint _bufferOffset = (jint) 0;
    361     jint _remaining;
    362     CTYPE *params = (CTYPE *) 0;
    363     int _needed = 0;
    364 
    365     params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
    366     _remaining /= sizeof(CTYPE);    // convert from bytes to item count
    367     _needed = getNeededCount(pname);
    368     // if we didn't find this pname, we just assume the user passed
    369     // an array of the right size -- this might happen with extensions
    370     // or if we forget an enum here.
    371     if (_needed>0 && _remaining < _needed) {
    372         _exception = 1;
    373         _exceptionType = "java/lang/IllegalArgumentException";
    374         _exceptionMessage = "remaining() < needed";
    375         goto exit;
    376     }
    377     if (params == NULL) {
    378         char * _paramsBase = (char *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
    379             _env, _array, (jboolean *) 0);
    380         params = (CTYPE *) (_paramsBase + _bufferOffset);
    381     }
    382     GET(
    383         (GLenum)pname,
    384         (CTYPE *)params
    385     );
    386 
    387 exit:
    388     if (_array) {
    389         releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
    390             _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE);
    391     }
    392     if (_exception) {
    393         jniThrowException(_env, _exceptionType, _exceptionMessage);
    394     }
    395 }
    396 
    397 // --------------------------------------------------------------------------
    398