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