• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
glVertexAttribPointerBounds(GLuint indx,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * pointer,GLsizei count)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
glVertexAttribIPointerBounds(GLuint indx,GLint size,GLenum type,GLsizei stride,const GLvoid * pointer,GLsizei count)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
nativeClassInit(JNIEnv * _env,jclass glImplClass)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 *
getPointer(JNIEnv * _env,jobject buffer,jarray * array,jint * remaining,jint * offset)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
releasePointer(JNIEnv * _env,jarray array,void * data,jboolean commit)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 *
getDirectBufferPointer(JNIEnv * _env,jobject buffer)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  */
getNeededCount(GLint pname)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
get(JNIEnv * _env,jobject _this,jint pname,JTYPEARRAY params_ref,jint offset)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
getarray(JNIEnv * _env,jobject _this,jint pname,jobject params_buf)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     _needed = getNeededCount(pname);
276     // if we didn't find this pname, we just assume the user passed
277     // an array of the right size -- this might happen with extensions
278     // or if we forget an enum here.
279     if (_needed>0 && _remaining < _needed) {
280         _exception = 1;
281         _exceptionType = "java/lang/IllegalArgumentException";
282         _exceptionMessage = "remaining() < needed";
283         goto exit;
284     }
285     if (params == NULL) {
286         char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
287         params = (CTYPE *) (_paramsBase + _bufferOffset);
288     }
289     GET(
290         (GLenum)pname,
291         (CTYPE *)params
292     );
293 
294 exit:
295     if (_array) {
296         releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
297     }
298     if (_exception) {
299         jniThrowException(_env, _exceptionType, _exceptionMessage);
300     }
301 }
302 
303 // --------------------------------------------------------------------------
304