com_google_android_gles_jni_EGLImpl.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/*
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
471