116 | * Wrapping is typically used for debugging purposes. 117 | *
118 | * The default value is null. 119 | * 120 | * @param glWrapper the new GLWrapper 121 | */ 122 | public void setGLWrapper(GLWrapper glWrapper) { 123 | mGLWrapper = glWrapper; 124 | } 125 | 126 | /** 127 | * Set the debug flags to a new value. The value is 128 | * constructed by OR-together zero or more 129 | * of the DEBUG_CHECK_* constants. The debug flags take effect 130 | * whenever a surface is created. The default value is zero. 131 | * 132 | * @param debugFlags the new debug flags 133 | * @see #DEBUG_CHECK_GL_ERROR 134 | * @see #DEBUG_LOG_GL_CALLS 135 | */ 136 | public void setDebugFlags(int debugFlags) { 137 | mDebugFlags = debugFlags; 138 | } 139 | 140 | /** 141 | * Get the current value of the debug flags. 142 | * 143 | * @return the current value of the debug flags. 144 | */ 145 | public int getDebugFlags() { 146 | return mDebugFlags; 147 | } 148 | 149 | /** 150 | * Control whether the EGL context is preserved when the GLTextureView is paused and 151 | * resumed. 152 | *
153 | * If set to true, then the EGL context may be preserved when the GLTextureView is paused. 154 | * Whether the EGL context is actually preserved or not depends upon whether the 155 | * Android device that the program is running on can support an arbitrary number of EGL 156 | * contexts or not. Devices that can only support a limited number of EGL contexts must 157 | * release the EGL context in order to allow multiple applications to share the GPU. 158 | *
159 | * If set to false, the EGL context will be released when the GLTextureView is paused, 160 | * and recreated when the GLTextureView is resumed. 161 | *
162 | *
163 | * The default is false. 164 | * 165 | * @param preserveOnPause preserve the EGL context when paused 166 | */ 167 | public void setPreserveEGLContextOnPause(boolean preserveOnPause) { 168 | mPreserveEGLContextOnPause = preserveOnPause; 169 | } 170 | 171 | /** 172 | * @return true if the EGL context will be preserved when paused 173 | */ 174 | public boolean getPreserveEGLContextOnPause() { 175 | return mPreserveEGLContextOnPause; 176 | } 177 | 178 | /** 179 | * Set the renderer associated with this view. Also starts the thread that 180 | * will call the renderer, which in turn causes the rendering to start. 181 | *
This method should be called once and only once in the life-cycle of 182 | * a GLTextureView. 183 | *
The following GLTextureView methods can only be called before 184 | * setRenderer is called: 185 | *
191 | * The following GLTextureView methods can only be called after 192 | * setRenderer is called: 193 | *
If this method is 223 | * called, it must be called before {@link #setRenderer(Renderer)} 224 | * is called. 225 | *
226 | * If this method is not called, then by default 227 | * a context will be created with no shared context and 228 | * with a null attribute list. 229 | */ 230 | public void setEGLContextFactory(EGLContextFactory factory) { 231 | checkRenderThreadState(); 232 | mEGLContextFactory = factory; 233 | } 234 | 235 | /** 236 | * Install a custom EGLWindowSurfaceFactory. 237 | *
If this method is 238 | * called, it must be called before {@link #setRenderer(Renderer)} 239 | * is called. 240 | *
241 | * If this method is not called, then by default 242 | * a window surface will be created with a null attribute list. 243 | */ 244 | public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) { 245 | checkRenderThreadState(); 246 | mEGLWindowSurfaceFactory = factory; 247 | } 248 | 249 | /** 250 | * Install a custom EGLConfigChooser. 251 | *
If this method is 252 | * called, it must be called before {@link #setRenderer(Renderer)} 253 | * is called. 254 | *
255 | * If no setEGLConfigChooser method is called, then by default the 256 | * view will choose an EGLConfig that is compatible with the current 257 | * android.view.Surface, with a depth buffer depth of 258 | * at least 16 bits. 259 | * 260 | * @param configChooser 261 | */ 262 | public void setEGLConfigChooser(EGLConfigChooser configChooser) { 263 | checkRenderThreadState(); 264 | mEGLConfigChooser = configChooser; 265 | } 266 | 267 | /** 268 | * Install a config chooser which will choose a config 269 | * as close to 16-bit RGB as possible, with or without an optional depth 270 | * buffer as close to 16-bits as possible. 271 | *
If this method is 272 | * called, it must be called before {@link #setRenderer(Renderer)} 273 | * is called. 274 | *
275 | * If no setEGLConfigChooser method is called, then by default the 276 | * view will choose an RGB_888 surface with a depth buffer depth of 277 | * at least 16 bits. 278 | * 279 | * @param needDepth 280 | */ 281 | public void setEGLConfigChooser(boolean needDepth) { 282 | setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth)); 283 | } 284 | 285 | /** 286 | * Install a config chooser which will choose a config 287 | * with at least the specified depthSize and stencilSize, 288 | * and exactly the specified redSize, greenSize, blueSize and alphaSize. 289 | *
If this method is 290 | * called, it must be called before {@link #setRenderer(Renderer)} 291 | * is called. 292 | *
293 | * If no setEGLConfigChooser method is called, then by default the 294 | * view will choose an RGB_888 surface with a depth buffer depth of 295 | * at least 16 bits. 296 | */ 297 | public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, 298 | int alphaSize, int depthSize, int stencilSize) { 299 | setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, 300 | blueSize, alphaSize, depthSize, stencilSize)); 301 | } 302 | 303 | /** 304 | * Inform the default EGLContextFactory and default EGLConfigChooser 305 | * which EGLContext client version to pick. 306 | *
Use this method to create an OpenGL ES 2.0-compatible context. 307 | * Example: 308 | *
309 | * public MyView(Context context) {
310 | * super(context);
311 | * setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.
312 | * setRenderer(new MyRenderer());
313 | * }
314 | *
315 | * Note: Activities which require OpenGL ES 2.0 should indicate this by 316 | * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the activity's 317 | * AndroidManifest.xml file. 318 | *
If this method is called, it must be called before {@link #setRenderer(Renderer)} 319 | * is called. 320 | *
This method only affects the behavior of the default EGLContexFactory and the 321 | * default EGLConfigChooser. If 322 | * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied 323 | * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context. 324 | * If 325 | * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied 326 | * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config. 327 | * 328 | * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0 329 | */ 330 | public void setEGLContextClientVersion(int version) { 331 | checkRenderThreadState(); 332 | mEGLContextClientVersion = version; 333 | } 334 | 335 | /** 336 | * Set the rendering mode. When renderMode is 337 | * RENDERMODE_CONTINUOUSLY, the renderer is called 338 | * repeatedly to re-render the scene. When renderMode 339 | * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface 340 | * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY. 341 | *
342 | * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance 343 | * by allowing the GPU and CPU to idle when the view does not need to be updated. 344 | *
345 | * This method can only be called after {@link #setRenderer(Renderer)} 346 | * 347 | * @param renderMode one of the RENDERMODE_X constants 348 | * @see #RENDERMODE_CONTINUOUSLY 349 | * @see #RENDERMODE_WHEN_DIRTY 350 | */ 351 | public void setRenderMode(int renderMode) { 352 | mGLThread.setRenderMode(renderMode); 353 | } 354 | 355 | /** 356 | * Get the current rendering mode. May be called 357 | * from any thread. Must not be called before a renderer has been set. 358 | * 359 | * @return the current rendering mode. 360 | * @see #RENDERMODE_CONTINUOUSLY 361 | * @see #RENDERMODE_WHEN_DIRTY 362 | */ 363 | public int getRenderMode() { 364 | return mGLThread.getRenderMode(); 365 | } 366 | 367 | /** 368 | * Request that the renderer render a frame. 369 | * This method is typically used when the render mode has been set to 370 | * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. 371 | * May be called 372 | * from any thread. Must not be called before a renderer has been set. 373 | */ 374 | public void requestRender() { 375 | mGLThread.requestRender(); 376 | } 377 | 378 | /** 379 | * This method is part of the SurfaceHolder.Callback interface, and is 380 | * not normally called or subclassed by clients of GLTextureView. 381 | */ 382 | public void surfaceCreated(SurfaceTexture texture) { 383 | mGLThread.surfaceCreated(); 384 | } 385 | 386 | /** 387 | * This method is part of the SurfaceHolder.Callback interface, and is 388 | * not normally called or subclassed by clients of GLTextureView. 389 | */ 390 | public void surfaceDestroyed(SurfaceTexture texture) { 391 | // Surface will be destroyed when we return 392 | mGLThread.surfaceDestroyed(); 393 | } 394 | 395 | /** 396 | * This method is part of the SurfaceHolder.Callback interface, and is 397 | * not normally called or subclassed by clients of GLTextureView. 398 | */ 399 | public void surfaceChanged(SurfaceTexture texture, int format, int w, int h) { 400 | mGLThread.onWindowResize(w, h); 401 | } 402 | 403 | /** 404 | * Inform the view that the activity is paused. The owner of this view must 405 | * call this method when the activity is paused. Calling this method will 406 | * pause the rendering thread. 407 | * Must not be called before a renderer has been set. 408 | */ 409 | public void onPause() { 410 | mGLThread.onPause(); 411 | } 412 | 413 | /** 414 | * Inform the view that the activity is resumed. The owner of this view must 415 | * call this method when the activity is resumed. Calling this method will 416 | * recreate the OpenGL display and resume the rendering 417 | * thread. 418 | * Must not be called before a renderer has been set. 419 | */ 420 | public void onResume() { 421 | mGLThread.onResume(); 422 | } 423 | 424 | /** 425 | * Queue a runnable to be run on the GL rendering thread. This can be used 426 | * to communicate with the Renderer on the rendering thread. 427 | * Must not be called before a renderer has been set. 428 | * 429 | * @param r the runnable to be run on the GL rendering thread. 430 | */ 431 | public void queueEvent(Runnable r) { 432 | mGLThread.queueEvent(r); 433 | } 434 | 435 | /** 436 | * This method is used as part of the View class and is not normally 437 | * called or subclassed by clients of GLTextureView. 438 | */ 439 | @Override 440 | protected void onAttachedToWindow() { 441 | super.onAttachedToWindow(); 442 | if (LOG_ATTACH_DETACH) { 443 | Log.d(TAG, "onAttachedToWindow reattach =" + mDetached); 444 | } 445 | if (mDetached && (mRenderer != null)) { 446 | int renderMode = RENDERMODE_CONTINUOUSLY; 447 | if (mGLThread != null) { 448 | renderMode = mGLThread.getRenderMode(); 449 | } 450 | mGLThread = new GLThread(mThisWeakRef); 451 | if (renderMode != RENDERMODE_CONTINUOUSLY) { 452 | mGLThread.setRenderMode(renderMode); 453 | } 454 | mGLThread.start(); 455 | } 456 | mDetached = false; 457 | } 458 | 459 | /** 460 | * This method is used as part of the View class and is not normally 461 | * called or subclassed by clients of GLTextureView. 462 | * Must not be called before a renderer has been set. 463 | */ 464 | @Override 465 | protected void onDetachedFromWindow() { 466 | if (LOG_ATTACH_DETACH) { 467 | Log.d(TAG, "onDetachedFromWindow"); 468 | } 469 | if (mGLThread != null) { 470 | mGLThread.requestExitAndWait(); 471 | } 472 | mDetached = true; 473 | super.onDetachedFromWindow(); 474 | } 475 | 476 | public void onLayoutChange(View v, int left, int top, int right, int bottom, 477 | int oldLeft, int oldTop, int oldRight, int oldBottom) { 478 | surfaceChanged(getSurfaceTexture(), 0, right - left, bottom - top); 479 | } 480 | 481 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 482 | surfaceCreated(surface); 483 | surfaceChanged(surface, 0, width, height); 484 | } 485 | 486 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 487 | surfaceChanged(surface, 0, width, height); 488 | } 489 | 490 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 491 | surfaceDestroyed(surface); 492 | return true; 493 | } 494 | 495 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 496 | requestRender(); 497 | } 498 | 499 | // ---------------------------------------------------------------------- 500 | 501 | /** 502 | * An interface used to wrap a GL interface. 503 | *
Typically 504 | * used for implementing debugging and tracing on top of the default 505 | * GL interface. You would typically use this by creating your own class 506 | * that implemented all the GL methods by delegating to another GL instance. 507 | * Then you could add your own behavior before or after calling the 508 | * delegate. All the GLWrapper would do was instantiate and return the 509 | * wrapper GL instance: 510 | *
511 | * class MyGLWrapper implements GLWrapper {
512 | * GL wrap(GL gl) {
513 | * return new MyGLImplementation(gl);
514 | * }
515 | * static class MyGLImplementation implements GL,GL10,GL11,... {
516 | * ...
517 | * }
518 | * }
519 | *
520 | *
521 | * @see #setGLWrapper(GLWrapper)
522 | */
523 | public interface GLWrapper {
524 | /**
525 | * Wraps a gl interface in another gl interface.
526 | *
527 | * @param gl a GL interface that is to be wrapped.
528 | * @return either the input argument or another GL object that wraps the input argument.
529 | */
530 | GL wrap(GL gl);
531 | }
532 |
533 | /**
534 | * A generic renderer interface.
535 | * 536 | * The renderer is responsible for making OpenGL calls to render a frame. 537 | *
538 | * GLTextureView clients typically create their own classes that implement 539 | * this interface, and then call {@link GLTextureView#setRenderer} to 540 | * register the renderer with the GLTextureView. 541 | *
542 | *
543 | *
For more information about how to use OpenGL, read the 546 | * OpenGL developer guide.
547 | *549 | *
557 | *
572 | * Called when the rendering thread 573 | * starts and whenever the EGL context is lost. The EGL context will typically 574 | * be lost when the Android device awakes after going to sleep. 575 | *
576 | * Since this method is called at the beginning of rendering, as well as 577 | * every time the EGL context is lost, this method is a convenient place to put 578 | * code to create resources that need to be created when the rendering 579 | * starts, and that need to be recreated when the EGL context is lost. 580 | * Textures are an example of a resource that you might want to create 581 | * here. 582 | *
583 | * Note that when the EGL context is lost, all OpenGL resources associated 584 | * with that context will be automatically deleted. You do not need to call 585 | * the corresponding "glDelete" methods such as glDeleteTextures to 586 | * manually delete these lost resources. 587 | *
588 | *
589 | * @param gl the GL interface. Use instanceof to
590 | * test if the interface supports GL11 or higher interfaces.
591 | * @param config the EGLConfig of the created surface. Can be used
592 | * to create matching pbuffers.
593 | */
594 | void onSurfaceCreated(GL10 gl, EGLConfig config);
595 |
596 | /**
597 | * Called when the surface changed size.
598 | *
599 | * Called after the surface is created and whenever 600 | * the OpenGL ES surface size changes. 601 | *
602 | * Typically you will set your viewport here. If your camera 603 | * is fixed then you could also set your projection matrix here: 604 | *
605 | * void onSurfaceChanged(GL10 gl, int width, int height) {
606 | * gl.glViewport(0, 0, width, height);
607 | * // for a fixed camera, set the projection too
608 | * float ratio = (float) width / height;
609 | * gl.glMatrixMode(GL10.GL_PROJECTION);
610 | * gl.glLoadIdentity();
611 | * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
612 | * }
613 | *
614 | *
615 | * @param gl the GL interface. Use instanceof to
616 | * test if the interface supports GL11 or higher interfaces.
617 | * @param width
618 | * @param height
619 | */
620 | void onSurfaceChanged(GL10 gl, int width, int height);
621 |
622 | /**
623 | * Called to draw the current frame.
624 | * 625 | * This method is responsible for drawing the current frame. 626 | *
627 | * The implementation of this method typically looks like this: 628 | *
629 | * void onDrawFrame(GL10 gl) {
630 | * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
631 | * //... other gl calls to render the scene ...
632 | * }
633 | *
634 | *
635 | * @param gl the GL interface. Use instanceof to
636 | * test if the interface supports GL11 or higher interfaces.
637 | */
638 | void onDrawFrame(GL10 gl);
639 |
640 | void onSurfaceDestroyed(GL10 gl);
641 | }
642 |
643 | /**
644 | * An interface for customizing the eglCreateContext and eglDestroyContext calls.
645 | * 646 | * This interface must be implemented by clients wishing to call 647 | * {@link GLTextureView#setEGLContextFactory(EGLContextFactory)} 648 | */ 649 | public interface EGLContextFactory { 650 | EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig); 651 | 652 | void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context); 653 | } 654 | 655 | private class DefaultContextFactory implements EGLContextFactory { 656 | private int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 657 | 658 | public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) { 659 | int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion, 660 | EGL10.EGL_NONE}; 661 | 662 | return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, 663 | mEGLContextClientVersion != 0 ? attrib_list : null); 664 | } 665 | 666 | public void destroyContext(EGL10 egl, EGLDisplay display, 667 | EGLContext context) { 668 | if (!egl.eglDestroyContext(display, context)) { 669 | Log.e("DefaultContextFactory", "display:" + display + " context: " + context); 670 | if (LOG_THREADS) { 671 | Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId()); 672 | } 673 | EglHelper.throwEglException("eglDestroyContex", egl.eglGetError()); 674 | } 675 | } 676 | } 677 | 678 | /** 679 | * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls. 680 | *
681 | * This interface must be implemented by clients wishing to call 682 | * {@link GLTextureView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)} 683 | */ 684 | public interface EGLWindowSurfaceFactory { 685 | /** 686 | * @return null if the surface cannot be constructed. 687 | */ 688 | EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, 689 | Object nativeWindow); 690 | 691 | void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface); 692 | } 693 | 694 | private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory { 695 | 696 | public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, 697 | EGLConfig config, Object nativeWindow) { 698 | EGLSurface result = null; 699 | try { 700 | result = egl.eglCreateWindowSurface(display, config, nativeWindow, null); 701 | } catch (IllegalArgumentException e) { 702 | // This exception indicates that the surface flinger surface 703 | // is not valid. This can happen if the surface flinger surface has 704 | // been torn down, but the application has not yet been 705 | // notified via SurfaceHolder.Callback.surfaceDestroyed. 706 | // In theory the application should be notified first, 707 | // but in practice sometimes it is not. See b/4588890 708 | Log.e(TAG, "eglCreateWindowSurface", e); 709 | } 710 | return result; 711 | } 712 | 713 | public void destroySurface(EGL10 egl, EGLDisplay display, 714 | EGLSurface surface) { 715 | egl.eglDestroySurface(display, surface); 716 | } 717 | } 718 | 719 | /** 720 | * An interface for choosing an EGLConfig configuration from a list of 721 | * potential configurations. 722 | *
723 | * This interface must be implemented by clients wishing to call
724 | * {@link GLTextureView#setEGLConfigChooser(EGLConfigChooser)}
725 | */
726 | public interface EGLConfigChooser {
727 | /**
728 | * Choose a configuration from the list. Implementors typically
729 | * implement this method by calling
730 | * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
731 | * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
732 | *
733 | * @param egl the EGL10 for the current display.
734 | * @param display the current display.
735 | * @return the chosen configuration.
736 | */
737 | EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
738 | }
739 |
740 | private abstract class BaseConfigChooser
741 | implements EGLConfigChooser {
742 | public BaseConfigChooser(int[] configSpec) {
743 | mConfigSpec = filterConfigSpec(configSpec);
744 | }
745 |
746 | public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
747 | int[] num_config = new int[1];
748 | if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
749 | num_config)) {
750 | throw new IllegalArgumentException("eglChooseConfig failed");
751 | }
752 |
753 | int numConfigs = num_config[0];
754 |
755 | if (numConfigs <= 0) {
756 | throw new IllegalArgumentException(
757 | "No configs match configSpec");
758 | }
759 |
760 | EGLConfig[] configs = new EGLConfig[numConfigs];
761 | if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
762 | num_config)) {
763 | throw new IllegalArgumentException("eglChooseConfig#2 failed");
764 | }
765 | EGLConfig config = chooseConfig(egl, display, configs);
766 | if (config == null) {
767 | throw new IllegalArgumentException("No config chosen");
768 | }
769 | return config;
770 | }
771 |
772 | abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
773 | EGLConfig[] configs);
774 |
775 | protected int[] mConfigSpec;
776 |
777 | private int[] filterConfigSpec(int[] configSpec) {
778 | if (mEGLContextClientVersion != 2) {
779 | return configSpec;
780 | }
781 | /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
782 | * And we know the configSpec is well formed.
783 | */
784 | int len = configSpec.length;
785 | int[] newConfigSpec = new int[len + 2];
786 | System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
787 | newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
788 | newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
789 | newConfigSpec[len + 1] = EGL10.EGL_NONE;
790 | return newConfigSpec;
791 | }
792 | }
793 |
794 | /**
795 | * Choose a configuration with exactly the specified r,g,b,a sizes,
796 | * and at least the specified depth and stencil sizes.
797 | */
798 | private class ComponentSizeChooser extends BaseConfigChooser {
799 | public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
800 | int alphaSize, int depthSize, int stencilSize) {
801 | super(new int[]{
802 | EGL10.EGL_RED_SIZE, redSize,
803 | EGL10.EGL_GREEN_SIZE, greenSize,
804 | EGL10.EGL_BLUE_SIZE, blueSize,
805 | EGL10.EGL_ALPHA_SIZE, alphaSize,
806 | EGL10.EGL_DEPTH_SIZE, depthSize,
807 | EGL10.EGL_STENCIL_SIZE, stencilSize,
808 | EGL10.EGL_NONE});
809 | mValue = new int[1];
810 | mRedSize = redSize;
811 | mGreenSize = greenSize;
812 | mBlueSize = blueSize;
813 | mAlphaSize = alphaSize;
814 | mDepthSize = depthSize;
815 | mStencilSize = stencilSize;
816 | }
817 |
818 | @Override
819 | public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
820 | EGLConfig[] configs) {
821 | for (EGLConfig config : configs) {
822 | int d = findConfigAttrib(egl, display, config,
823 | EGL10.EGL_DEPTH_SIZE, 0);
824 | int s = findConfigAttrib(egl, display, config,
825 | EGL10.EGL_STENCIL_SIZE, 0);
826 | if ((d >= mDepthSize) && (s >= mStencilSize)) {
827 | int r = findConfigAttrib(egl, display, config,
828 | EGL10.EGL_RED_SIZE, 0);
829 | int g = findConfigAttrib(egl, display, config,
830 | EGL10.EGL_GREEN_SIZE, 0);
831 | int b = findConfigAttrib(egl, display, config,
832 | EGL10.EGL_BLUE_SIZE, 0);
833 | int a = findConfigAttrib(egl, display, config,
834 | EGL10.EGL_ALPHA_SIZE, 0);
835 | if ((r == mRedSize) && (g == mGreenSize)
836 | && (b == mBlueSize) && (a == mAlphaSize)) {
837 | return config;
838 | }
839 | }
840 | }
841 | return null;
842 | }
843 |
844 | private int findConfigAttrib(EGL10 egl, EGLDisplay display,
845 | EGLConfig config, int attribute, int defaultValue) {
846 |
847 | if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
848 | return mValue[0];
849 | }
850 | return defaultValue;
851 | }
852 |
853 | private int[] mValue;
854 | // Subclasses can adjust these values:
855 | protected int mRedSize;
856 | protected int mGreenSize;
857 | protected int mBlueSize;
858 | protected int mAlphaSize;
859 | protected int mDepthSize;
860 | protected int mStencilSize;
861 | }
862 |
863 | /**
864 | * This class will choose a RGB_888 surface with
865 | * or without a depth buffer.
866 | */
867 | private class SimpleEGLConfigChooser extends ComponentSizeChooser {
868 | public SimpleEGLConfigChooser(boolean withDepthBuffer) {
869 | super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
870 | }
871 | }
872 |
873 | /**
874 | * An EGL helper class.
875 | */
876 |
877 | private static class EglHelper {
878 | public EglHelper(WeakReference
1113 | * All potentially blocking synchronization is done through the
1114 | * sGLThreadManager object. This avoids multiple-lock ordering issues.
1115 | */
1116 | static class GLThread extends Thread {
1117 | GLThread(WeakReference