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