1 #include <jni.h>
2 #include <nativehelper/JNIPlatformHelp.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
glVertexAttribPointerBounds(GLuint indx,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * pointer,GLsizei count)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
glVertexAttribIPointerBounds(GLuint indx,GLint size,GLenum type,GLsizei stride,const GLvoid * pointer,GLsizei count)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
nativeClassInit(JNIEnv * _env,jclass glImplClass)42 nativeClassInit(JNIEnv *_env, jclass glImplClass)
43 {
44 }
45 
46 static void *
getPointer(JNIEnv * _env,jobject buffer,jarray * array,jint * remaining,jint * offset)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:
Get(JNIEnv * _env,jbyteArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jbooleanArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jcharArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jshortArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jintArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jlongArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jfloatArray array,jboolean * is_copy)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:
Get(JNIEnv * _env,jdoubleArray array,jboolean * is_copy)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*
getArrayPointer(JNIEnv * _env,JTYPEARRAY array,jboolean * is_copy)118 getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) {
119     return ARRAYGETTER::Get(_env, array, is_copy);
120 }
121 
122 class ByteArrayReleaser {
123 public:
Release(JNIEnv * _env,jbyteArray array,jbyte * data,jboolean commit)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:
Release(JNIEnv * _env,jbooleanArray array,jboolean * data,jboolean commit)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:
Release(JNIEnv * _env,jcharArray array,jchar * data,jboolean commit)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:
Release(JNIEnv * _env,jshortArray array,jshort * data,jboolean commit)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:
Release(JNIEnv * _env,jintArray array,jint * data,jboolean commit)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:
Release(JNIEnv * _env,jlongArray array,jlong * data,jboolean commit)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:
Release(JNIEnv * _env,jfloatArray array,jfloat * data,jboolean commit)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:
Release(JNIEnv * _env,jdoubleArray array,jdouble * data,jboolean commit)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
releaseArrayPointer(JNIEnv * _env,JTYPEARRAY array,NTYPEARRAY data,jboolean commit)173 releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) {
174     ARRAYRELEASER::Release(_env, array, data, commit);
175 }
176 
177 static void
releasePointer(JNIEnv * _env,jarray array,void * data,jboolean commit)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 *
getDirectBufferPointer(JNIEnv * _env,jobject buffer)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  */
getNeededCount(GLint pname)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
get(JNIEnv * _env,jobject _this,jint pname,JTYPEARRAY params_ref,jint offset)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
getarray(JNIEnv * _env,jobject _this,jint pname,jobject params_buf)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