GLRootView.java revision f9a0a4306d589b4a4e20554fed512a603426bfa1
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.anim.CanvasAnimation; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.GalleryUtils; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.app.Activity; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.PixelFormat; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.opengl.GLSurfaceView; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Process; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.SystemClock; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.util.AttributeSet; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.util.DisplayMetrics; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.LinkedList; 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.locks.ReentrantLock; 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.egl.EGLConfig; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL10; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL11; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The root component of all <code>GLView</code>s. The rendering is done in GL 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// thread while the event handling is done in the main thread. To synchronize 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// the two threads, the entry points of this package need to synchronize on the 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// <code>GLRootView</code> instance unless it can be proved that the rendering 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// thread won't access the same thing as the method. The entry points include: 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (1) The public methods of HeadUpDisplay 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (2) The public methods of CameraHeadUpDisplay 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (3) The overridden methods in GLRootView. 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class GLRootView extends GLSurfaceView 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin implements GLSurfaceView.Renderer, GLRoot { 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "GLRootView"; 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final boolean DEBUG_FPS = false; 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mFrameCount = 0; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mFrameCountingStart = 0; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final boolean DEBUG_INVALIDATE = false; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mInvalidateColor = 0; 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final boolean DEBUG_DRAWING_STAT = false; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int FLAG_INITIALIZED = 1; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int FLAG_NEED_LAYOUT = 2; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private GL11 mGL; 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private GLCanvasImpl mCanvas; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private GLView mContentView; 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private DisplayMetrics mDisplayMetrics; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mFlags = FLAG_NEED_LAYOUT; 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mRenderRequested = false; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Rect mClipRect = new Rect(); 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mClipRetryCount = 0; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final GalleryEGLConfigChooser mEglConfigChooser = 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new GalleryEGLConfigChooser(); 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ArrayList<CanvasAnimation> mAnimations = 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new ArrayList<CanvasAnimation>(); 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final LinkedList<OnGLIdleListener> mIdleListeners = 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new LinkedList<OnGLIdleListener>(); 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final IdleRunner mIdleRunner = new IdleRunner(); 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ReentrantLock mRenderLock = new ReentrantLock(); 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int TARGET_FRAME_TIME = 33; 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mLastDrawFinishTime; 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mInDownState = false; 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GLRootView(Context context) { 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this(context, null); 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GLRootView(Context context, AttributeSet attrs) { 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(context, attrs); 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFlags |= FLAG_INITIALIZED; 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setBackgroundDrawable(null); 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setEGLConfigChooser(mEglConfigChooser); 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setRenderer(this); 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin getHolder().setFormat(PixelFormat.RGB_565); 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Uncomment this to enable gl error check. 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin //setDebugFlags(DEBUG_CHECK_GL_ERROR); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GalleryEGLConfigChooser getEGLConfigChooser() { 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mEglConfigChooser; 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean hasStencil() { 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return getEGLConfigChooser().getStencilBits() > 0; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void registerLaunchedAnimation(CanvasAnimation animation) { 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Register the newly launched animation so that we can set the start 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // time more precisely. (Usually, it takes much longer for first 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // rendering, so we set the animation start time as the time we 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // complete rendering) 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mAnimations.add(animation); 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addOnGLIdleListener(OnGLIdleListener listener) { 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mIdleListeners) { 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIdleListeners.addLast(listener); 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIdleRunner.enable(); 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setContentPane(GLView content) { 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentView == content) return; 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentView != null) { 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mInDownState) { 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long now = SystemClock.uptimeMillis(); 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MotionEvent cancelEvent = MotionEvent.obtain( 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentView.dispatchTouchEvent(cancelEvent); 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin cancelEvent.recycle(); 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInDownState = false; 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentView.detachFromRoot(); 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin BasicTexture.yieldAllTextures(); 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentView = content; 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (content != null) { 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin content.attachToRoot(this); 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin requestLayoutContentPane(); 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GLView getContentPane() { 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mContentView; 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void requestRender() { 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (DEBUG_INVALIDATE) { 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin StackTraceElement e = Thread.currentThread().getStackTrace()[4]; 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String caller = e.getFileName() + ":" + e.getLineNumber() + " "; 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.d(TAG, "invalidate: " + caller); 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mRenderRequested) return; 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderRequested = true; 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super.requestRender(); 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void requestLayoutContentPane() { 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.lock(); 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentView == null || (mFlags & FLAG_NEED_LAYOUT) != 0) return; 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // "View" system will invoke onLayout() for initialization(bug ?), we 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // have to ignore it since the GLThread is not ready yet. 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if ((mFlags & FLAG_INITIALIZED) == 0) return; 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFlags |= FLAG_NEED_LAYOUT; 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin requestRender(); 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } finally { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.unlock(); 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void layoutContentPane() { 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFlags &= ~FLAG_NEED_LAYOUT; 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int width = getWidth(); 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int height = getHeight(); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.i(TAG, "layout content pane " + width + "x" + height); 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentView != null && width != 0 && height != 0) { 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentView.layout(0, 0, width, height); 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Uncomment this to dump the view hierarchy. 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin //mContentView.dumpTree(""); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onLayout( 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean changed, int left, int top, int right, int bottom) { 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (changed) requestLayoutContentPane(); 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Called when the context is created, possibly after automatic destruction. 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This is a GLSurfaceView.Renderer callback 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSurfaceCreated(GL10 gl1, EGLConfig config) { 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin GL11 gl = (GL11) gl1; 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mGL != null) { 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The GL Object has changed 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.i(TAG, "GLObject has changed from " + mGL + " to " + gl); 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGL = gl; 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCanvas = new GLCanvasImpl(gl); 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!DEBUG_FPS) { 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Called when the OpenGL surface is recreated without destroying the 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * context. 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This is a GLSurfaceView.Renderer callback 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSurfaceChanged(GL10 gl1, int width, int height) { 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.i(TAG, "onSurfaceChanged: " + width + "x" + height 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin + ", gl10: " + gl1.toString()); 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin GalleryUtils.setRenderThread(); 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin GL11 gl = (GL11) gl1; 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(mGL == gl); 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCanvas.setSize(width, height); 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mClipRect.set(0, 0, width, height); 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mClipRetryCount = 2; 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void outputFps() { 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long now = System.nanoTime(); 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mFrameCountingStart == 0) { 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFrameCountingStart = now; 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if ((now - mFrameCountingStart) > 1000000000) { 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.d(TAG, "fps: " + (double) mFrameCount 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 1000000000 / (now - mFrameCountingStart)); 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFrameCountingStart = now; 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFrameCount = 0; 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ++mFrameCount; 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onDrawFrame(GL10 gl) { 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.lock(); 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onDrawFrameLocked(gl); 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } finally { 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.unlock(); 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long end = SystemClock.uptimeMillis(); 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLastDrawFinishTime != 0) { 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long wait = mLastDrawFinishTime + TARGET_FRAME_TIME - end; 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (wait > 0) { 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SystemClock.sleep(wait); 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLastDrawFinishTime = SystemClock.uptimeMillis(); 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void onDrawFrameLocked(GL10 gl) { 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (DEBUG_FPS) outputFps(); 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // release the unbound textures and deleted buffers. 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCanvas.deleteRecycledResources(); 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // reset texture upload limit 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UploadedTexture.resetUploadLimit(); 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderRequested = false; 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if ((mFlags & FLAG_NEED_LAYOUT) != 0) layoutContentPane(); 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // OpenGL seems having a bug causing us not being able to reset the 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // scissor box in "onSurfaceChanged()". We have to do it in the second 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // onDrawFrame(). 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mClipRetryCount > 0) { 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin --mClipRetryCount; 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Rect clip = mClipRect; 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glScissor(clip.left, clip.top, clip.width(), clip.height()); 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCanvas.setCurrentAnimationTimeMillis(SystemClock.uptimeMillis()); 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentView != null) { 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentView.render(mCanvas); 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mAnimations.isEmpty()) { 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long now = SystemClock.uptimeMillis(); 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = mAnimations.size(); i < n; i++) { 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mAnimations.get(i).setStartTime(now); 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mAnimations.clear(); 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (UploadedTexture.uploadLimitReached()) { 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin requestRender(); 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mIdleListeners) { 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mRenderRequested && !mIdleListeners.isEmpty()) { 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIdleRunner.enable(); 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (DEBUG_INVALIDATE) { 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCanvas.fillRect(10, 10, 5, 5, mInvalidateColor); 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInvalidateColor = ~mInvalidateColor; 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (DEBUG_DRAWING_STAT) { 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCanvas.dumpStatisticsAndClear(); 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean dispatchTouchEvent(MotionEvent event) { 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int action = event.getAction(); 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (action == MotionEvent.ACTION_CANCEL 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || action == MotionEvent.ACTION_UP) { 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInDownState = false; 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (!mInDownState && action != MotionEvent.ACTION_DOWN) { 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.lock(); 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If this has been detached from root, we don't need to handle event 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean handled = mContentView != null 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mContentView.dispatchTouchEvent(event); 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (action == MotionEvent.ACTION_DOWN && handled) { 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInDownState = true; 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return handled; 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } finally { 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.unlock(); 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public DisplayMetrics getDisplayMetrics() { 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mDisplayMetrics == null) { 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDisplayMetrics = new DisplayMetrics(); 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ((Activity) getContext()).getWindowManager() 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .getDefaultDisplay().getMetrics(mDisplayMetrics); 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mDisplayMetrics; 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GLCanvas getCanvas() { 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mCanvas; 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class IdleRunner implements Runnable { 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // true if the idle runner is in the queue 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mActive = false; 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void run() { 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin OnGLIdleListener listener; 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mIdleListeners) { 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActive = false; 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mRenderRequested) return; 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIdleListeners.isEmpty()) return; 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin listener = mIdleListeners.removeFirst(); 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.lock(); 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!listener.onGLIdle(GLRootView.this, mCanvas)) return; 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } finally { 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.unlock(); 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mIdleListeners) { 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIdleListeners.addLast(listener); 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin enable(); 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void enable() { 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Who gets the flag can add it to the queue 399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActive) return; 400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActive = true; 401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin queueEvent(this); 402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void lockRenderThread() { 407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.lock(); 408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void unlockRenderThread() { 412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRenderLock.unlock(); 413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 415