From 722a96cbb4236fa8b4d84f7b1e1b64b30e656cd0 Mon Sep 17 00:00:00 2001 From: Jack Palevich <> Date: Wed, 8 Apr 2009 19:02:20 -0700 Subject: AI 145244: Fully document GLSurfaceView and related classes. BUG=1766685 Automated import of CL 145244 --- opengl/java/android/opengl/GLSurfaceView.java | 400 ++++++++++++++++++++++---- 1 file changed, 349 insertions(+), 51 deletions(-) (limited to 'opengl/java') diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 7fb85854bc31..43011d7f9ccc 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -16,7 +16,6 @@ package android.opengl; -import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.concurrent.Semaphore; @@ -38,32 +37,163 @@ import android.view.SurfaceView; /** * An implementation of SurfaceView that uses the dedicated surface for - * displaying an OpenGL animation. This allows the animation to run in a - * separate thread, without requiring that it be driven by the update mechanism - * of the view hierarchy. + * displaying OpenGL rendering. + *
+ * A GLSurfaceView provides the following features: + *
+ *
+ * Typically you use GLSurfaceView by subclassing it and overriding one or more of the + * View system input event methods. If your application does not need to override event + * methods then GLSurfaceView can be used as-is. For the most part + * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing. + * For example, unlike a regular View, drawing is delegated to a separate Renderer object which + * is registered with the GLSurfaceView + * using the {@link #setRenderer(Renderer)} call. + *
+ *
+ *
+ * By default GLSurfaceView chooses an available surface that's closest to a 16-bit R5G6B5 surface + * with a 16-bit depth buffer and no stencil. If you would prefer a different surface (for example, + * if you do not need a depth buffer) you can override the default behavior by calling one of the + * setEGLConfigChooser methods. + *
+ *
+ *
+ *
+ *
+ *
+ * To handle an event you will typically subclass GLSurfaceView and override the + * appropriate method, just as you would with any other View. However, when handling + * the event, you may need to communicate with the Renderer object + * that's running in the rendering thread. You can do this using any + * standard Java cross-thread communication mechanism. In addition, + * one relatively easy way to communicate with your renderer is + * to call + * {@link #queueEvent(Runnable)}. For example: + *
+ * class MyGLSurfaceView extends GLSurfaceView {
+ *
+ * private MyRenderer mMyRenderer;
+ *
+ * public void start() {
+ * mMyRenderer = ...;
+ * setRenderer(mMyRenderer);
+ * }
+ *
+ * public boolean onKeyDown(int keyCode, KeyEvent event) {
+ * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ * queueEvent(new Runnable() {
+ * // This method will be called on the rendering
+ * // thread:
+ * public void run() {
+ * mMyRenderer.handleDpadCenter();
+ * }});
+ * return true;
+ * }
+ * return super.onKeyDown(keyCode, event);
+ * }
+ * }
+ *
*
- * The application-specific rendering code is delegated to a GLView.Renderer
- * instance.
*/
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+ /**
+ * The renderer only renders
+ * when the surface is created, or when {@link #requestRender} is called.
+ *
+ * @see #getRenderMode()
+ * @see #setRenderMode(int)
+ */
public final static int RENDERMODE_WHEN_DIRTY = 0;
+ /**
+ * The renderer is called
+ * continuously to re-render the scene.
+ *
+ * @see #getRenderMode()
+ * @see #setRenderMode(int)
+ * @see #requestRender()
+ */
public final static int RENDERMODE_CONTUOUSLY = 1;
/**
- * Check glError() after every GL call.
+ * Check glError() after every GL call and throw an exception if glError indicates
+ * that an error has occurred. This can be used to help track down which OpenGL ES call
+ * is causing an error.
+ *
+ * @see #getDebugFlags
+ * @see #setDebugFlags
*/
public final static int DEBUG_CHECK_GL_ERROR = 1;
/**
* Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
+ *
+ * @see #getDebugFlags
+ * @see #setDebugFlags
*/
public final static int DEBUG_LOG_GL_CALLS = 2;
+ /**
+ * Standard View constructor. In order to render something, you
+ * must call {@link #setRenderer} to register a renderer.
+ */
public GLSurfaceView(Context context) {
super(context);
init();
}
+ /**
+ * Standard View constructor. In order to render something, you
+ * must call {@link #setRenderer} to register a renderer.
+ */
public GLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
@@ -78,8 +208,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
/**
- * Set the glWrapper to a new value. The current glWrapper is used
- * whenever a surface is created. The default value is null.
+ * Set the glWrapper. If the glWrapper is not null, its
+ * {@link GLWrapper#wrap(GL)} method is called
+ * whenever a surface is created. A GLWrapper can be used to wrap
+ * the GL object that's passed to the renderer. Wrapping a GL
+ * object enables examining and modifying the behavior of the
+ * GL calls made by the renderer.
+ * + * Wrapping is typically used for debugging purposes. + *
+ * The default value is null. * @param glWrapper the new GLWrapper */ public void setGLWrapper(GLWrapper glWrapper) { @@ -87,7 +225,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } /** - * Set the debug flags to a new value. The debug flags take effect + * Set the debug flags to a new value. The value is + * constructed by OR-together zero or more + * of the DEBUG_CHECK_* constants. The debug flags take effect * whenever a surface is created. The default value is zero. * @param debugFlags the new debug flags * @see #DEBUG_CHECK_GL_ERROR @@ -97,13 +237,39 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mDebugFlags = debugFlags; } + /** + * Get the current value of the debug flags. + * @return the current value of the debug flags. + */ public int getDebugFlags() { return mDebugFlags; } /** - * Set the renderer associated with this view. Can only be called once. - * @param renderer + * Set the renderer associated with this view. Also starts the thread that + * will call the renderer, which in turn causes the rendering to start. + *
This method should be called once and only once in the life-cycle of + * a GLSurfaceView. + *
The following GLSurfaceView methods can only be called before + * setRenderer is called: + *
+ * The following GLSurfaceView methods can only be called after + * setRenderer is called: + *
If this method is + * called, it must be called before {@link #setRenderer(Renderer)} * is called. *
- * The supplied configChooser will be used to choose a configuration. + * If no setEGLConfigChooser method is called, then by default the + * view will choose a config as close to 16-bit RGB as possible, with + * a depth buffer as close to 16 bits as possible. * @param configChooser */ public void setEGLConfigChooser(EGLConfigChooser configChooser) { @@ -134,17 +303,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } /** - * Set the EGLConfigChooser associated with this view. If this method is - * called, it must be called before {@link #setRenderer(Renderer)} - * is called. - *
- * This method installs a config chooser which will choose a config + * Install a config chooser which will choose a config * as close to 16-bit RGB as possible, with or without an optional depth * buffer as close to 16-bits as possible. + *
If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. *
- * If no setEGLConfigChooser method is called, then by default the + * If no setEGLConfigChooser method is called, then by default the * view will choose a config as close to 16-bit RGB as possible, with - * a depth buffer as close to 16-bits as possible. + * a depth buffer as close to 16 bits as possible. * * @param needDepth */ @@ -153,13 +321,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } /** - * Set the EGLConfigChooser associated with this view. If this method is + * Install a config chooser which will choose a config + * with at least the specified component sizes, and as close + * to the specified component sizes as possible. + *
If this method is * called, it must be called before {@link #setRenderer(Renderer)} * is called. *
- * This method installs a config chooser which will choose a config - * with at least the specified component sizes, and as close - * to the specified component sizes as possible. + * If no setEGLConfigChooser method is called, then by default the + * view will choose a config as close to 16-bit RGB as possible, with + * a depth buffer as close to 16 bits as possible. * */ public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, @@ -168,12 +339,20 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback blueSize, alphaSize, depthSize, stencilSize)); } /** - * Set the rendering mode. When the renderMode is - * RENDERMODE_CONTINUOUSLY, the renderer is called - * repeatedly to re-render the scene. When the rendermode + * Set the rendering mode. When renderMode is + * RENDERMODE_CONTUOUSLY, the renderer is called + * repeatedly to re-render the scene. When renderMode * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface - * is created, or when requestRender is called. Defaults to RENDERMODE_CONTINUOUSLY. + * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTUOUSLY. + *
+ * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance + * by allowing the GPU and CPU to idle when the view does not need to be updated. + *
+ * This method can only be called after {@link #setRenderer(Renderer)} + * * @param renderMode one of the RENDERMODE_X constants + * @see #RENDERMODE_CONTUOUSLY + * @see #RENDERMODE_WHEN_DIRTY */ public void setRenderMode(int renderMode) { mGLThread.setRenderMode(renderMode); @@ -182,38 +361,55 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback /** * Get the current rendering mode. May be called * from any thread. Must not be called before a renderer has been set. - * @return true if the renderer will render continuously. + * @return the current rendering mode. + * @see #RENDERMODE_CONTUOUSLY + * @see #RENDERMODE_WHEN_DIRTY */ public int getRenderMode() { return mGLThread.getRenderMode(); } /** - * Request that the renderer render a frame. May be called - * from any thread. Must not be called before a renderer has been set. + * Request that the renderer render a frame. * This method is typically used when the render mode has been set to - * false, so that frames are only rendered on demand. + * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. + * May be called + * from any thread. Must not be called before a renderer has been set. */ public void requestRender() { mGLThread.requestRender(); } + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ public void surfaceCreated(SurfaceHolder holder) { mGLThread.surfaceCreated(); } + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return mGLThread.surfaceDestroyed(); } + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { mGLThread.onWindowResize(w, h); } /** * Inform the view that the activity is paused. The owner of this view must - * call this method when the activity is paused. + * call this method when the activity is paused. Calling this method will + * pause the rendering thread. + * Must not be called before a renderer has been set. */ public void onPause() { mGLThread.onPause(); @@ -221,20 +417,30 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback /** * Inform the view that the activity is resumed. The owner of this view must - * call this method when the activity is resumed. + * call this method when the activity is resumed. Calling this method will + * recreate the OpenGL display and resume the rendering + * thread. + * Must not be called before a renderer has been set. */ public void onResume() { mGLThread.onResume(); } /** - * Queue an "event" to be run on the GL rendering thread. + * Queue a runnable to be run on the GL rendering thread. This can be used + * to communicate with the Renderer on the rendering thread. + * Must not be called before a renderer has been set. * @param r the runnable to be run on the GL rendering thread. */ public void queueEvent(Runnable r) { mGLThread.queueEvent(r); } + /** + * This method is used as part of the View class and is not normally + * called or subclassed by clients of GLSurfaceView. + * Must not be called before a renderer has been set. + */ @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); @@ -243,40 +449,129 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback // ---------------------------------------------------------------------- + /** + * An interface used to wrap a GL interface. + *
Typically + * used for implementing debugging and tracing on top of the default + * GL interface. You would typically use this by creating your own class + * that implemented all the GL methods by delegating to another GL instance. + * Then you could add your own behavior before or after calling the + * delegate. All the GLWrapper would do was instantiate and return the + * wrapper GL instance: + *
+ * class MyGLWrapper implements GLWrapper {
+ * GL wrap(GL gl) {
+ * return new MyGLImplementation(gl);
+ * }
+ * static class MyGLImplementation implements GL,GL10,GL11,... {
+ * ...
+ * }
+ * }
+ *
+ * @see #setGLWrapper(GLWrapper)
+ */
public interface GLWrapper {
- GL wrap(GL gl);
+ /**
+ * Wraps a gl interface in another gl interface.
+ * @param gl a GL interface that is to be wrapped.
+ * @return either the input argument or another GL object that wraps the input argument.
+ */
+ GL wrap(GL gl);
}
- // ----------------------------------------------------------------------
-
/**
* A generic renderer interface.
+ * + * The renderer is responsible for making OpenGL calls to render a frame. + *
+ * GLSurfaceView clients typically create their own classes that implement + * this interface, and then call {@link GLSurfaceView#setRenderer} to + * register the renderer with the GLSurfaceView. + *
+ *
+ *
+ * Called when the rendering thread + * starts and whenever the EGL context is lost. The context will typically + * be lost when the Android device awakes after going to sleep. + *
+ * Since this method is called at the beginning of rendering, as well as + * every time the EGL context is lost, this method is a convenient place to put + * code to create resources that need to be created when the rendering + * starts, and that need to be recreated when the EGL context is lost. + * Textures are an example of a resource that you might want to create + * here. + *
+ * Note that when the EGL context is lost, all OpenGL resources associated + * with that context will be automatically deleted. You do not need to call + * the corresponding "glDelete" methods such as glDeleteTextures to + * manually delete these lost resources. + *
* @param gl the GL interface. Use instanceof to
* test if the interface supports GL11 or higher interfaces.
* @param config the EGLConfig of the created surface. Can be used
* to create matching pbuffers.
*/
void onSurfaceCreated(GL10 gl, EGLConfig config);
+
/**
- * Surface changed size.
+ * Called when the surface changed size.
+ *
* Called after the surface is created and whenever - * the OpenGL ES surface size changes. Set your viewport here. + * the OpenGL ES surface size changes. + *
+ * Typically you will set your viewport here. If your camera + * is fixed then you could also set your projection matrix here: + *
+ * void onSurfaceChanged(GL10 gl, int width, int height) {
+ * gl.glViewport(0, 0, width, height);
+ * // for a fixed camera, set the projection too
+ * float ratio = (float) width / height;
+ * gl.glMatrixMode(GL10.GL_PROJECTION);
+ * gl.glLoadIdentity();
+ * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+ * }
+ *
* @param gl the GL interface. Use instanceof to
* test if the interface supports GL11 or higher interfaces.
* @param width
* @param height
*/
void onSurfaceChanged(GL10 gl, int width, int height);
+
/**
- * Draw the current frame.
+ * Called to draw the current frame.
+ * + * This method is responsible for drawing the current frame. + *
+ * The implementation of this method typically looks like this: + *
+ * void onDrawFrame(GL10 gl) {
+ * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+ * //... other gl calls to render the scene ...
+ * }
+ *
* @param gl the GL interface. Use instanceof to
* test if the interface supports GL11 or higher interfaces.
*/
@@ -284,15 +579,18 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
/**
- * An interface for choosing a configuration from a list of
+ * An interface for choosing an EGLConfig configuration from a list of
* potential configurations.
- *
+ * + * This interface must be implemented by clients wishing to call + * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)} */ public interface EGLConfigChooser { /** * Choose a configuration from the list. Implementors typically * implement this method by calling - * {@link EGL10#eglChooseConfig} and iterating through the results. + * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the + * EGL specification available from The Khronos Group to learn how to call eglChooseConfig. * @param egl the EGL10 for the current display. * @param display the current display. * @return the chosen configuration. -- cgit v1.2.3-59-g8ed1b