1#include "jni.h" 2#include "JNIHelp.h" 3#include <android_runtime/AndroidRuntime.h> 4#include <utils/misc.h> 5#include <assert.h> 6 7static int initialized = 0; 8 9static jclass nioAccessClass; 10static jclass bufferClass; 11static jmethodID getBasePointerID; 12static jmethodID getBaseArrayID; 13static jmethodID getBaseArrayOffsetID; 14static jfieldID positionID; 15static jfieldID limitID; 16static jfieldID elementSizeShiftID; 17 18 19/* special calls implemented in Android's GLES wrapper used to more 20 * efficiently bound-check passed arrays */ 21extern "C" { 22#ifdef GL_VERSION_ES_CM_1_1 23GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, 24 const GLvoid *ptr, GLsizei count); 25GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, 26 const GLvoid *pointer, GLsizei count); 27GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, 28 GLsizei stride, const GLvoid *pointer, GLsizei count); 29GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, 30 GLsizei stride, const GLvoid *pointer, GLsizei count); 31GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type, 32 GLsizei stride, const GLvoid *pointer, GLsizei count); 33GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type, 34 GLsizei stride, const GLvoid *pointer, GLsizei count); 35GL_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 39static 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 45static 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 54static void 55nativeClassInit(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 76static void * 77getPointer(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 103static void 104releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) 105{ 106 _env->ReleasePrimitiveArrayCritical(array, data, 107 commit ? 0 : JNI_ABORT); 108} 109 110static void * 111getDirectBufferPointer(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 */ 137static 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 206template <typename JTYPEARRAY, typename CTYPE, void GET(GLenum, CTYPE*)> 207static void 208get 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 250exit: 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 261template <typename CTYPE, void GET(GLenum, CTYPE*)> 262static void 263getarray 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 295exit: 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