blob: fbbd85216608acf84ad1c0131511c9a05c839e36 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <android_runtime/AndroidRuntime.h>
19#include <utils/misc.h>
20
21#include <EGL/egl.h>
22#include <GLES/gl.h>
23
24#include <ui/EGLNativeWindowSurface.h>
25#include <ui/Surface.h>
26#include <SkBitmap.h>
27#include <SkPixelRef.h>
28
29namespace android {
30
31static jclass gDisplay_class;
32static jclass gContext_class;
33static jclass gSurface_class;
34static jclass gConfig_class;
35
36static jmethodID gConfig_ctorID;
37
38static jfieldID gDisplay_EGLDisplayFieldID;
39static jfieldID gContext_EGLContextFieldID;
40static jfieldID gSurface_EGLSurfaceFieldID;
41static jfieldID gSurface_NativePixelRefFieldID;
42static jfieldID gConfig_EGLConfigFieldID;
43static jfieldID gSurface_SurfaceFieldID;
44static jfieldID gBitmap_NativeBitmapFieldID;
45
46static __attribute__((noinline))
47void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
48{
49 jclass npeClazz = env->FindClass(exc);
50 env->ThrowNew(npeClazz, msg);
51}
52
53static __attribute__((noinline))
54bool hasException(JNIEnv *env) {
55 if (env->ExceptionCheck() != 0) {
56 env->ExceptionDescribe();
57 return true;
58 }
59 return false;
60}
61
62static __attribute__((noinline))
63jclass make_globalref(JNIEnv* env, const char classname[]) {
64 jclass c = env->FindClass(classname);
65 return (jclass)env->NewGlobalRef(c);
66}
67
68static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
69 if (!o) return EGL_NO_DISPLAY;
70 return (EGLDisplay)env->GetIntField(o, gDisplay_EGLDisplayFieldID);
71}
72static inline EGLSurface getSurface(JNIEnv* env, jobject o) {
73 if (!o) return EGL_NO_SURFACE;
74 return (EGLSurface)env->GetIntField(o, gSurface_EGLSurfaceFieldID);
75}
76static inline EGLContext getContext(JNIEnv* env, jobject o) {
77 if (!o) return EGL_NO_CONTEXT;
78 return (EGLContext)env->GetIntField(o, gContext_EGLContextFieldID);
79}
80static inline EGLConfig getConfig(JNIEnv* env, jobject o) {
81 if (!o) return 0;
82 return (EGLConfig)env->GetIntField(o, gConfig_EGLConfigFieldID);
83}
84static void nativeClassInit(JNIEnv *_env, jclass eglImplClass)
85{
86 gDisplay_class = make_globalref(_env, "com/google/android/gles_jni/EGLDisplayImpl");
87 gContext_class = make_globalref(_env, "com/google/android/gles_jni/EGLContextImpl");
88 gSurface_class = make_globalref(_env, "com/google/android/gles_jni/EGLSurfaceImpl");
89 gConfig_class = make_globalref(_env, "com/google/android/gles_jni/EGLConfigImpl");
90
91 gConfig_ctorID = _env->GetMethodID(gConfig_class, "<init>", "(I)V");
92
93 gDisplay_EGLDisplayFieldID = _env->GetFieldID(gDisplay_class, "mEGLDisplay", "I");
94 gContext_EGLContextFieldID = _env->GetFieldID(gContext_class, "mEGLContext", "I");
95 gSurface_EGLSurfaceFieldID = _env->GetFieldID(gSurface_class, "mEGLSurface", "I");
96 gSurface_NativePixelRefFieldID = _env->GetFieldID(gSurface_class, "mNativePixelRef", "I");
97 gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I");
98
99 jclass surface_class = _env->FindClass("android/view/Surface");
100 gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I");
101
102 jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
103 gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I");
104}
105
106jboolean jni_eglInitialize(JNIEnv *_env, jobject _this, jobject display,
107 jintArray major_minor) {
108
109 EGLDisplay dpy = getDisplay(_env, display);
110 jboolean success = eglInitialize(dpy, NULL, NULL);
111 if (success && major_minor) {
112 int len = _env->GetArrayLength(major_minor);
113 if (len) {
114 // we're exposing only EGL 1.0
115 jint* base = (jint *)_env->GetPrimitiveArrayCritical(major_minor, (jboolean *)0);
116 if (len >= 1) base[0] = 1;
117 if (len >= 2) base[1] = 0;
118 _env->ReleasePrimitiveArrayCritical(major_minor, base, JNI_ABORT);
119 }
120 }
121 return success;
122}
123
124jboolean jni_eglQueryContext(JNIEnv *_env, jobject _this, jobject display,
125 jobject context, jint attribute, jintArray value) {
126 EGLDisplay dpy = getDisplay(_env, display);
127 EGLContext ctx = getContext(_env, context);
128 if (value == NULL) {
129 doThrow(_env, "java/lang/NullPointerException");
130 return JNI_FALSE;
131 }
132 jboolean success = JNI_FALSE;
133 int len = _env->GetArrayLength(value);
134 if (len) {
135 jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
136 success = eglQueryContext(dpy, ctx, attribute, base);
137 _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
138 }
139 return success;
140}
141
142jboolean jni_eglQuerySurface(JNIEnv *_env, jobject _this, jobject display,
143 jobject surface, jint attribute, jintArray value) {
144 EGLDisplay dpy = getDisplay(_env, display);
145 EGLContext sur = getSurface(_env, surface);
146 if (value == NULL) {
147 doThrow(_env, "java/lang/NullPointerException");
148 return JNI_FALSE;
149 }
150 jboolean success = JNI_FALSE;
151 int len = _env->GetArrayLength(value);
152 if (len) {
153 jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
154 success = eglQuerySurface(dpy, sur, attribute, base);
155 _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
156 }
157 return success;
158}
159
160jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
161 jintArray attrib_list, jobjectArray configs, jint config_size, jintArray num_config) {
162 EGLDisplay dpy = getDisplay(_env, display);
163 if (attrib_list==NULL || configs==NULL || num_config==NULL) {
164 doThrow(_env, "java/lang/NullPointerException");
165 return JNI_FALSE;
166 }
167 jboolean success = JNI_FALSE;
168 jint* attrib_base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
169 jint* num_base = (jint *)_env->GetPrimitiveArrayCritical(num_config, (jboolean *)0);
170 EGLConfig nativeConfigs[config_size];
171 success = eglChooseConfig(dpy, attrib_base, nativeConfigs, config_size, num_base);
172 int num = num_base[0];
173 _env->ReleasePrimitiveArrayCritical(num_config, num_base, JNI_ABORT);
174 _env->ReleasePrimitiveArrayCritical(attrib_list, attrib_base, JNI_ABORT);
175 if (success) {
176 for (int i=0 ; i<num ; i++) {
177 jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
178 _env->SetObjectArrayElement(configs, i, obj);
179 }
180 }
181 return success;
182}
183
184jint jni_eglCreateContext(JNIEnv *_env, jobject _this, jobject display,
185 jobject config, jobject share_context, jintArray attrib_list) {
186 EGLDisplay dpy = getDisplay(_env, display);
187 EGLConfig cnf = getConfig(_env, config);
188 EGLContext shr = getContext(_env, share_context);
189 jint* base = 0;
190 if (attrib_list) {
191 // XXX: if array is malformed, we should return an NPE instead of segfault
192 base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
193 }
194 EGLContext ctx = eglCreateContext(dpy, cnf, shr, base);
195 if (attrib_list) {
196 _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
197 }
198 return (jint)ctx;
199}
200
201jint jni_eglCreatePbufferSurface(JNIEnv *_env, jobject _this, jobject display,
202 jobject config, jintArray attrib_list) {
203 EGLDisplay dpy = getDisplay(_env, display);
204 EGLConfig cnf = getConfig(_env, config);
205 jint* base = 0;
206 if (attrib_list) {
207 // XXX: if array is malformed, we should return an NPE instead of segfault
208 base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
209 }
210 EGLSurface sur = eglCreatePbufferSurface(dpy, cnf, base);
211 if (attrib_list) {
212 _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
213 }
214 return (jint)sur;
215}
216
217static PixelFormat convertPixelFormat(SkBitmap::Config format)
218{
219 switch (format) {
220 case SkBitmap::kARGB_8888_Config: return PIXEL_FORMAT_RGBA_8888;
221 case SkBitmap::kARGB_4444_Config: return PIXEL_FORMAT_RGBA_4444;
222 case SkBitmap::kRGB_565_Config: return PIXEL_FORMAT_RGB_565;
223 case SkBitmap::kA8_Config: return PIXEL_FORMAT_A_8;
224 default: return PIXEL_FORMAT_NONE;
225 }
226}
227
228void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_sur,
229 jobject display, jobject config, jobject native_pixmap,
230 jintArray attrib_list)
231{
232 EGLDisplay dpy = getDisplay(_env, display);
233 EGLConfig cnf = getConfig(_env, config);
234 jint* base = 0;
235
236 SkBitmap const * nativeBitmap =
237 (SkBitmap const *)_env->GetIntField(native_pixmap,
238 gBitmap_NativeBitmapFieldID);
239 SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
240 if (ref == NULL) {
241 doThrow(_env, "java/lang/NullPointerException", "Bitmap has no PixelRef");
242 return;
243 }
244
245 ref->safeRef();
246 ref->lockPixels();
247
248 egl_native_pixmap_t pixmap;
249 pixmap.version = sizeof(pixmap);
250 pixmap.width = nativeBitmap->width();
251 pixmap.height = nativeBitmap->height();
252 pixmap.stride = nativeBitmap->rowBytes() / nativeBitmap->bytesPerPixel();
253 pixmap.format = convertPixelFormat(nativeBitmap->config());
254 pixmap.data = (uint8_t*)ref->pixels();
255
256 if (attrib_list) {
257 // XXX: if array is malformed, we should return an NPE instead of segfault
258 base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
259 }
260 EGLSurface sur = eglCreatePixmapSurface(dpy, cnf, &pixmap, base);
261 if (attrib_list) {
262 _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
263 }
264
265 if (sur != EGL_NO_SURFACE) {
266 _env->SetIntField(out_sur, gSurface_EGLSurfaceFieldID, (int)sur);
267 _env->SetIntField(out_sur, gSurface_NativePixelRefFieldID, (int)ref);
268 } else {
269 ref->unlockPixels();
270 ref->safeUnref();
271 }
272}
273
274jint jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject display,
275 jobject config, jobject native_window, jintArray attrib_list) {
276 EGLDisplay dpy = getDisplay(_env, display);
277 EGLContext cnf = getConfig(_env, config);
278 Surface* window = 0;
279 if (native_window == NULL) {
280not_valid_surface:
281 doThrow(_env, "java/lang/NullPointerException",
282 "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface");
283 return 0;
284 }
285 window = (Surface*)_env->GetIntField(native_window, gSurface_SurfaceFieldID);
286 if (window == NULL)
287 goto not_valid_surface;
288
289 jint* base = 0;
290 if (attrib_list) {
291 // XXX: if array is malformed, we should return an NPE instead of segfault
292 base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
293 }
294 EGLSurface sur = eglCreateWindowSurface(dpy, cnf, new EGLNativeWindowSurface(window), base);
295 if (attrib_list) {
296 _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
297 }
298 return (jint)sur;
299}
300
301jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display,
302 jobject config, jint attribute, jintArray value) {
303 EGLDisplay dpy = getDisplay(_env, display);
304 EGLContext cnf = getConfig(_env, config);
305 if (value == NULL) {
306 doThrow(_env, "java/lang/NullPointerException");
307 return JNI_FALSE;
308 }
309 jboolean success = JNI_FALSE;
310 int len = _env->GetArrayLength(value);
311 if (len) {
312 jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
313 success = eglGetConfigAttrib(dpy, cnf, attribute, base);
314 _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
315 }
316 return success;
317}
318
319jboolean jni_eglGetConfigs(JNIEnv *_env, jobject _this, jobject display,
320 jobjectArray configs, jint config_size, jintArray num_config) {
321 EGLDisplay dpy = getDisplay(_env, display);
322 jboolean success = JNI_FALSE;
323 if (num_config == NULL) {
324 doThrow(_env, "java/lang/NullPointerException");
325 return JNI_FALSE;
326 }
327 jint* num_base = (jint *)_env->GetPrimitiveArrayCritical(num_config, (jboolean *)0);
328 EGLConfig nativeConfigs[config_size];
329 success = eglGetConfigs(dpy, configs ? nativeConfigs : 0, config_size, num_base);
330 int num = num_base[0];
331 _env->ReleasePrimitiveArrayCritical(num_config, num_base, JNI_ABORT);
332
333 if (success && configs) {
334 for (int i=0 ; i<num ; i++) {
335 jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
336 _env->SetObjectArrayElement(configs, i, obj);
337 }
338 }
339 return success;
340}
341
342jint jni_eglGetError(JNIEnv *_env, jobject _this) {
343 EGLint error = eglGetError();
344 return error;
345}
346
347jint jni_eglGetCurrentContext(JNIEnv *_env, jobject _this) {
348 return (jint)eglGetCurrentContext();
349}
350
351jint jni_eglGetCurrentDisplay(JNIEnv *_env, jobject _this) {
352 return (jint)eglGetCurrentDisplay();
353}
354
355jint jni_eglGetCurrentSurface(JNIEnv *_env, jobject _this, jint readdraw) {
356 return (jint)eglGetCurrentSurface(readdraw);
357}
358
359jboolean jni_eglDestroyContext(JNIEnv *_env, jobject _this, jobject display, jobject context) {
360 EGLDisplay dpy = getDisplay(_env, display);
361 EGLContext ctx = getContext(_env, context);
362 return eglDestroyContext(dpy, ctx);
363}
364
365jboolean jni_eglDestroySurface(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
366 EGLDisplay dpy = getDisplay(_env, display);
367 EGLSurface sur = getSurface(_env, surface);
368
369 if (sur) {
370 SkPixelRef* ref = (SkPixelRef*)(_env->GetIntField(surface,
371 gSurface_NativePixelRefFieldID));
372 if (ref) {
373 ref->unlockPixels();
374 ref->safeUnref();
375 }
376 }
377 return eglDestroySurface(dpy, sur);
378}
379
380jint jni_eglGetDisplay(JNIEnv *_env, jobject _this, jobject native_display) {
381 return (jint)eglGetDisplay(EGL_DEFAULT_DISPLAY);
382}
383
384jboolean jni_eglMakeCurrent(JNIEnv *_env, jobject _this, jobject display, jobject draw, jobject read, jobject context) {
385 EGLDisplay dpy = getDisplay(_env, display);
386 EGLSurface sdr = getSurface(_env, draw);
387 EGLSurface srd = getSurface(_env, read);
388 EGLContext ctx = getContext(_env, context);
389 return eglMakeCurrent(dpy, sdr, srd, ctx);
390}
391
392jstring jni_eglQueryString(JNIEnv *_env, jobject _this, jobject display, jint name) {
393 EGLDisplay dpy = getDisplay(_env, display);
394 const char* chars = eglQueryString(dpy, name);
395 return _env->NewStringUTF(chars);
396}
397
398jboolean jni_eglSwapBuffers(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
399 EGLDisplay dpy = getDisplay(_env, display);
400 EGLSurface sur = getSurface(_env, surface);
401 return eglSwapBuffers(dpy, sur);
402}
403
404jboolean jni_eglTerminate(JNIEnv *_env, jobject _this, jobject display) {
405 EGLDisplay dpy = getDisplay(_env, display);
406 return eglTerminate(dpy);
407}
408
409jboolean jni_eglCopyBuffers(JNIEnv *_env, jobject _this, jobject display,
410 jobject surface, jobject native_pixmap) {
411 // TODO: implement me
412 return JNI_FALSE;
413}
414
415jboolean jni_eglWaitGL(JNIEnv *_env, jobject _this) {
416 return eglWaitGL();
417}
418
419jboolean jni_eglWaitNative(JNIEnv *_env, jobject _this, jint engine, jobject bindTarget) {
420 return eglWaitNative(engine);
421}
422
423
424static const char *classPathName = "com/google/android/gles_jni/EGLImpl";
425
426#define DISPLAY "Ljavax/microedition/khronos/egl/EGLDisplay;"
427#define CONTEXT "Ljavax/microedition/khronos/egl/EGLContext;"
428#define CONFIG "Ljavax/microedition/khronos/egl/EGLConfig;"
429#define SURFACE "Ljavax/microedition/khronos/egl/EGLSurface;"
430#define OBJECT "Ljava/lang/Object;"
431#define STRING "Ljava/lang/String;"
432
433static JNINativeMethod methods[] = {
434{"_nativeClassInit","()V", (void*)nativeClassInit },
435{"eglWaitGL", "()Z", (void*)jni_eglWaitGL },
436{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
437{"eglQueryContext", "(" DISPLAY CONTEXT "I[I)Z", (void*)jni_eglQueryContext },
438{"eglQuerySurface", "(" DISPLAY SURFACE "I[I)Z", (void*)jni_eglQuerySurface },
439{"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
440{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
441{"eglGetConfigs", "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },
442{"eglTerminate", "(" DISPLAY ")Z", (void*)jni_eglTerminate },
443{"eglCopyBuffers", "(" DISPLAY SURFACE OBJECT ")Z", (void*)jni_eglCopyBuffers },
444{"eglWaitNative", "(I" OBJECT ")Z", (void*)jni_eglWaitNative },
445{"eglGetError", "()I", (void*)jni_eglGetError },
446{"eglGetConfigAttrib", "(" DISPLAY CONFIG "I[I)Z", (void*)jni_eglGetConfigAttrib },
447{"_eglGetDisplay", "(" OBJECT ")I", (void*)jni_eglGetDisplay },
448{"_eglGetCurrentContext", "()I", (void*)jni_eglGetCurrentContext },
449{"_eglGetCurrentDisplay", "()I", (void*)jni_eglGetCurrentDisplay },
450{"_eglGetCurrentSurface", "(I)I", (void*)jni_eglGetCurrentSurface },
451{"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
452{"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
453{"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
454{"eglDestroyContext", "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
455{"eglDestroySurface", "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
456{"eglMakeCurrent", "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
457{"eglQueryString", "(" DISPLAY "I)" STRING, (void*)jni_eglQueryString },
458{"eglSwapBuffers", "(" DISPLAY SURFACE ")Z", (void*)jni_eglSwapBuffers },
459};
460
461} // namespace android
462
463int register_com_google_android_gles_jni_EGLImpl(JNIEnv *_env)
464{
465 int err;
466 err = android::AndroidRuntime::registerNativeMethods(_env,
467 android::classPathName, android::methods, NELEM(android::methods));
468 return err;
469}
470