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