diff options
Diffstat (limited to 'opengl/java/android')
| -rw-r--r-- | opengl/java/android/opengl/ETC1Util.java | 2 | ||||
| -rw-r--r-- | opengl/java/android/opengl/GLSurfaceView.java | 329 | ||||
| -rw-r--r-- | opengl/java/android/opengl/GLUtils.java | 13 | ||||
| -rw-r--r-- | opengl/java/android/opengl/Group.java | 155 | ||||
| -rw-r--r-- | opengl/java/android/opengl/Material.java | 120 | ||||
| -rw-r--r-- | opengl/java/android/opengl/Object3D.java | 245 | ||||
| -rw-r--r-- | opengl/java/android/opengl/Texture.java | 135 |
7 files changed, 220 insertions, 779 deletions
diff --git a/opengl/java/android/opengl/ETC1Util.java b/opengl/java/android/opengl/ETC1Util.java index 3629d41..e343c97 100644 --- a/opengl/java/android/opengl/ETC1Util.java +++ b/opengl/java/android/opengl/ETC1Util.java @@ -193,7 +193,7 @@ public class ETC1Util { int encodedImageSize = ETC1.getEncodedDataSize(width, height); ByteBuffer compressedImage = ByteBuffer.allocateDirect(encodedImageSize). order(ByteOrder.nativeOrder()); - ETC1.encodeImage(input, width, height, 3, stride, compressedImage); + ETC1.encodeImage(input, width, height, pixelSize, stride, compressedImage); return new ETC1Texture(width, height, compressedImage); } diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 8fd866c..8acbae3 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -17,6 +17,7 @@ package android.opengl; import java.io.Writer; +import java.lang.ref.WeakReference; import java.util.ArrayList; import javax.microedition.khronos.egl.EGL10; @@ -30,7 +31,6 @@ import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.content.pm.ConfigurationInfo; -import android.graphics.PixelFormat; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Log; @@ -169,8 +169,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private final static boolean LOG_RENDERER = false; private final static boolean LOG_RENDERER_DRAW_FRAME = false; private final static boolean LOG_EGL = false; - // Work-around for bug 2263168 - private final static boolean DRAW_TWICE_AFTER_SIZE_CHANGED = true; /** * The renderer only renders * when the surface is created, or when {@link #requestRender} is called. @@ -225,6 +223,19 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback init(); } + @Override + protected void finalize() throws Throwable { + try { + if (mGLThread != null) { + // GLThread may still be running if this view was never + // attached to a window. + mGLThread.requestExitAndWait(); + } + } finally { + super.finalize(); + } + } + private void init() { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed @@ -344,7 +355,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory(); } mRenderer = renderer; - mGLThread = new GLThread(renderer); + mGLThread = new GLThread(mThisWeakRef); mGLThread.start(); } @@ -575,7 +586,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (mGLThread != null) { renderMode = mGLThread.getRenderMode(); } - mGLThread = new GLThread(mRenderer); + mGLThread = new GLThread(mThisWeakRef); if (renderMode != RENDERMODE_CONTINUOUSLY) { mGLThread.setRenderMode(renderMode); } @@ -768,8 +779,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (LOG_THREADS) { Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId()); } - throw new RuntimeException("eglDestroyContext failed: " - + EGLLogWrapper.getErrorString(egl.eglGetError())); + EglHelper.throwEglException("eglDestroyContex", egl.eglGetError()); } } } @@ -972,9 +982,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * An EGL helper class. */ - private class EglHelper { - public EglHelper() { - + private static class EglHelper { + public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) { + mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; } /** @@ -1006,13 +1016,19 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if(!mEgl.eglInitialize(mEglDisplay, version)) { throw new RuntimeException("eglInitialize failed"); } - mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view == null) { + mEglConfig = null; + mEglContext = null; + } else { + mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay); - /* - * Create an EGL context. We want to do this as rarely as we can, because an - * EGL context is a somewhat heavy object. - */ - mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig); + /* + * Create an EGL context. We want to do this as rarely as we can, because an + * EGL context is a somewhat heavy object. + */ + mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig); + } if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) { mEglContext = null; throwEglException("createContext"); @@ -1024,11 +1040,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mEglSurface = null; } - /* - * React to the creation of a new surface by creating and returning an - * OpenGL interface that renders to that surface. + /** + * Create an egl surface for the current SurfaceHolder surface. If a surface + * already exists, destroy it before creating the new surface. + * + * @return true if the surface was created successfully. */ - public GL createSurface(SurfaceHolder holder) { + public boolean createSurface() { if (LOG_EGL) { Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId()); } @@ -1044,33 +1062,30 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (mEglConfig == null) { throw new RuntimeException("mEglConfig not initialized"); } + /* * The window size has changed, so we need to create a new * surface. */ - if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { - - /* - * Unbind and destroy the old EGL surface, if - * there is one. - */ - mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); - } + destroySurfaceImp(); /* * Create an EGL surface we can render into. */ - mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl, - mEglDisplay, mEglConfig, holder); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl, + mEglDisplay, mEglConfig, view.getHolder()); + } else { + mEglSurface = null; + } if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { int error = mEgl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); } - return null; + return false; } /* @@ -1078,76 +1093,72 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * the context is current and bound to a surface. */ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { - throwEglException("eglMakeCurrent"); + /* + * Could not make the context current, probably because the underlying + * SurfaceView surface has been destroyed. + */ + logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError()); + return false; } - GL gl = mEglContext.getGL(); - if (mGLWrapper != null) { - gl = mGLWrapper.wrap(gl); - } + return true; + } + + /** + * Create a GL object for the current EGL context. + * @return + */ + GL createGL() { - if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) { - int configFlags = 0; - Writer log = null; - if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { - configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; + GL gl = mEglContext.getGL(); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + if (view.mGLWrapper != null) { + gl = view.mGLWrapper.wrap(gl); } - if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { - log = new LogWriter(); + + if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) { + int configFlags = 0; + Writer log = null; + if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { + configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; + } + if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { + log = new LogWriter(); + } + gl = GLDebugHelper.wrap(gl, configFlags, log); } - gl = GLDebugHelper.wrap(gl, configFlags, log); } return gl; } - public void purgeBuffers() { - mEgl.eglMakeCurrent(mEglDisplay, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_CONTEXT); - mEgl.eglMakeCurrent(mEglDisplay, - mEglSurface, mEglSurface, - mEglContext); - } - /** * Display the current render surface. - * @return false if the context has been lost. + * @return the EGL error code from eglSwapBuffers. */ - public boolean swap() { + public int swap() { if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { - - /* - * Check for EGL_CONTEXT_LOST, which means the context - * and all associated data were lost (For instance because - * the device went to sleep). We need to sleep until we - * get a new surface. - */ - int error = mEgl.eglGetError(); - switch(error) { - case EGL11.EGL_CONTEXT_LOST: - return false; - case EGL10.EGL_BAD_NATIVE_WINDOW: - // The native window is bad, probably because the - // window manager has closed it. Ignore this error, - // on the expectation that the application will be closed soon. - Log.e("EglHelper", "eglSwapBuffers returned EGL_BAD_NATIVE_WINDOW. tid=" + Thread.currentThread().getId()); - break; - default: - throwEglException("eglSwapBuffers", error); - } + return mEgl.eglGetError(); } - return true; + return EGL10.EGL_SUCCESS; } public void destroySurface() { if (LOG_EGL) { Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId()); } + destroySurfaceImp(); + } + + private void destroySurfaceImp() { if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface); + } mEglSurface = null; } } @@ -1157,7 +1168,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId()); } if (mEglContext != null) { - mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext); + } mEglContext = null; } if (mEglDisplay != null) { @@ -1170,14 +1184,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback throwEglException(function, mEgl.eglGetError()); } - private void throwEglException(String function, int error) { - String message = function + " failed: " + EGLLogWrapper.getErrorString(error); + public static void throwEglException(String function, int error) { + String message = formatEglError(function, error); if (LOG_THREADS) { - Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " + message); + Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " + + message); } throw new RuntimeException(message); } + public static void logEglErrorAsWarning(String tag, String function, int error) { + Log.w(tag, formatEglError(function, error)); + } + + public static String formatEglError(String function, int error) { + return function + " failed: " + EGLLogWrapper.getErrorString(error); + } + + private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef; EGL10 mEgl; EGLDisplay mEglDisplay; EGLSurface mEglSurface; @@ -1195,14 +1219,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback * sGLThreadManager object. This avoids multiple-lock ordering issues. * */ - class GLThread extends Thread { - GLThread(Renderer renderer) { + static class GLThread extends Thread { + GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) { super(); mWidth = 0; mHeight = 0; mRequestRender = true; mRenderMode = RENDERMODE_CONTINUOUSLY; - mRenderer = renderer; + mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; } @Override @@ -1244,13 +1268,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } private void guardedRun() throws InterruptedException { - mEglHelper = new EglHelper(); + mEglHelper = new EglHelper(mGLSurfaceViewWeakRef); mHaveEglContext = false; mHaveEglSurface = false; try { GL10 gl = null; boolean createEglContext = false; boolean createEglSurface = false; + boolean createGlInterface = false; boolean lostEglContext = false; boolean sizeChanged = false; boolean wantRenderNotification = false; @@ -1273,7 +1298,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } // Update the pause state. + boolean pausing = false; if (mPaused != mRequestPaused) { + pausing = mRequestPaused; mPaused = mRequestPaused; sGLThreadManager.notifyAll(); if (LOG_PAUSE_RESUME) { @@ -1299,18 +1326,29 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback lostEglContext = false; } - // Do we need to release the EGL surface? - if (mHaveEglSurface && mPaused) { + // When pausing, release the EGL surface: + if (pausing && mHaveEglSurface) { if (LOG_SURFACE) { Log.i("GLThread", "releasing EGL surface because paused tid=" + getId()); } stopEglSurfaceLocked(); - if (!mPreserveEGLContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) { + } + + // When pausing, optionally release the EGL Context: + if (pausing && mHaveEglContext) { + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + boolean preserveEglContextOnPause = view == null ? + false : view.mPreserveEGLContextOnPause; + if (!preserveEglContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) { stopEglContextLocked(); if (LOG_SURFACE) { Log.i("GLThread", "releasing EGL context because paused tid=" + getId()); } } + } + + // When pausing, optionally terminate EGL: + if (pausing) { if (sGLThreadManager.shouldTerminateEGLWhenPausing()) { mEglHelper.finish(); if (LOG_SURFACE) { @@ -1319,7 +1357,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } - // Have we lost the surface view surface? + // Have we lost the SurfaceView surface? if ((! mHasSurface) && (! mWaitingForSurface)) { if (LOG_SURFACE) { Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId()); @@ -1328,6 +1366,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback stopEglSurfaceLocked(); } mWaitingForSurface = true; + mSurfaceIsBad = false; sGLThreadManager.notifyAll(); } @@ -1374,6 +1413,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (mHaveEglContext && !mHaveEglSurface) { mHaveEglSurface = true; createEglSurface = true; + createGlInterface = true; sizeChanged = true; } @@ -1384,20 +1424,17 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback h = mHeight; wantRenderNotification = true; if (LOG_SURFACE) { - Log.i("GLThread", "noticing that we want render notification tid=" + getId()); + Log.i("GLThread", + "noticing that we want render notification tid=" + + getId()); } - if (DRAW_TWICE_AFTER_SIZE_CHANGED) { - // We keep mRequestRender true so that we draw twice after the size changes. - // (Once because of mSizeChanged, the second time because of mRequestRender.) - // This forces the updated graphics onto the screen. - } else { - mRequestRender = false; - } + // Destroy and recreate the EGL surface. + createEglSurface = true; + mSizeChanged = false; - } else { - mRequestRender = false; } + mRequestRender = false; sGLThreadManager.notifyAll(); break; } @@ -1410,6 +1447,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback + " mHaveEglSurface: " + mHaveEglSurface + " mPaused: " + mPaused + " mHasSurface: " + mHasSurface + + " mSurfaceIsBad: " + mSurfaceIsBad + " mWaitingForSurface: " + mWaitingForSurface + " mWidth: " + mWidth + " mHeight: " + mHeight @@ -1430,20 +1468,31 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (LOG_SURFACE) { Log.w("GLThread", "egl createSurface"); } - gl = (GL10) mEglHelper.createSurface(getHolder()); - if (gl == null) { - // Couldn't create a surface. Quit quietly. - break; + if (!mEglHelper.createSurface()) { + synchronized(sGLThreadManager) { + mSurfaceIsBad = true; + sGLThreadManager.notifyAll(); + } + continue; } - sGLThreadManager.checkGLDriver(gl); createEglSurface = false; } + if (createGlInterface) { + gl = (GL10) mEglHelper.createGL(); + + sGLThreadManager.checkGLDriver(gl); + createGlInterface = false; + } + if (createEglContext) { if (LOG_RENDERER) { Log.w("GLThread", "onSurfaceCreated"); } - mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); + } createEglContext = false; } @@ -1451,20 +1500,44 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (LOG_RENDERER) { Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")"); } - mEglHelper.purgeBuffers(); - mRenderer.onSurfaceChanged(gl, w, h); + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mRenderer.onSurfaceChanged(gl, w, h); + } sizeChanged = false; } if (LOG_RENDERER_DRAW_FRAME) { Log.w("GLThread", "onDrawFrame tid=" + getId()); } - mRenderer.onDrawFrame(gl); - if (!mEglHelper.swap()) { - if (LOG_SURFACE) { - Log.i("GLThread", "egl context lost tid=" + getId()); + { + GLSurfaceView view = mGLSurfaceViewWeakRef.get(); + if (view != null) { + view.mRenderer.onDrawFrame(gl); } - lostEglContext = true; + } + int swapError = mEglHelper.swap(); + switch (swapError) { + case EGL10.EGL_SUCCESS: + break; + case EGL11.EGL_CONTEXT_LOST: + if (LOG_SURFACE) { + Log.i("GLThread", "egl context lost tid=" + getId()); + } + lostEglContext = true; + break; + default: + // Other errors typically mean that the current surface is bad, + // probably because the SurfaceView surface has been destroyed, + // but we haven't been notified yet. + // Log the error to help developers understand why rendering stopped. + EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError); + + synchronized(sGLThreadManager) { + mSurfaceIsBad = true; + sGLThreadManager.notifyAll(); + } + break; } if (wantRenderNotification) { @@ -1488,7 +1561,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } private boolean readyToDraw() { - return (!mPaused) && mHasSurface + return (!mPaused) && mHasSurface && (!mSurfaceIsBad) && (mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY)); } @@ -1603,9 +1676,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback // Wait for thread to react to resize and render a frame while (! mExited && !mPaused && !mRenderComplete - && (mGLThread != null && mGLThread.ableToDraw())) { + && ableToDraw()) { if (LOG_SURFACE) { - Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + mGLThread.getId()); + Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId()); } try { sGLThreadManager.wait(); @@ -1658,6 +1731,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private boolean mRequestPaused; private boolean mPaused; private boolean mHasSurface; + private boolean mSurfaceIsBad; private boolean mWaitingForSurface; private boolean mHaveEglContext; private boolean mHaveEglSurface; @@ -1668,11 +1742,19 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private boolean mRequestRender; private boolean mRenderComplete; private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); + private boolean mSizeChanged = true; // End of member variables protected by the sGLThreadManager monitor. - private Renderer mRenderer; private EglHelper mEglHelper; + + /** + * Set once at thread construction time, nulled out when the parent view is garbage + * called. This weak reference allows the GLSurfaceView to be garbage collected while + * the GLThread is still alive. + */ + private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef; + } static class LogWriter extends Writer { @@ -1788,7 +1870,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback ! renderer.startsWith(kMSM7K_RENDERER_PREFIX); notifyAll(); } - mLimitedGLESContexts = !mMultipleGLESContextsAllowed || renderer.startsWith(kADRENO); + mLimitedGLESContexts = !mMultipleGLESContextsAllowed; if (LOG_SURFACE) { Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = " + mMultipleGLESContextsAllowed @@ -1814,6 +1896,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } + /** + * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides + * support for hardware-accelerated views, therefore multiple EGL contexts are + * supported on all Android 3.0+ EGL drivers. + */ private boolean mGLESVersionCheckComplete; private int mGLESVersion; private boolean mGLESDriverCheckComplete; @@ -1822,13 +1909,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private static final int kGLES_20 = 0x20000; private static final String kMSM7K_RENDERER_PREFIX = "Q3Dimension MSM7500 "; - private static final String kADRENO = "Adreno"; private GLThread mEglOwner; } private static final GLThreadManager sGLThreadManager = new GLThreadManager(); - private boolean mSizeChanged = true; + private final WeakReference<GLSurfaceView> mThisWeakRef = + new WeakReference<GLSurfaceView>(this); private GLThread mGLThread; private Renderer mRenderer; private boolean mDetached; diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java index 125c56e..1527f22 100644 --- a/opengl/java/android/opengl/GLUtils.java +++ b/opengl/java/android/opengl/GLUtils.java @@ -227,9 +227,9 @@ public final class GLUtils { /** * Return a string for the EGL error code, or the hex representation * if the error is unknown. - * + * * @param error The EGL error to convert into a String. - * + * * @return An error string corresponding to the EGL error code. */ public static String getEGLErrorString(int error) { @@ -269,6 +269,14 @@ public final class GLUtils { } } + /** + * Enable tracing of OpenGL functions for this application. + * @hide + */ + public static void enableTracing() { + native_enableTracing(); + } + native private static void nativeClassInit(); native private static int native_getInternalFormat(Bitmap bitmap); @@ -277,4 +285,5 @@ public final class GLUtils { Bitmap bitmap, int type, int border); native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset, Bitmap bitmap, int format, int type); + native private static void native_enableTracing(); } diff --git a/opengl/java/android/opengl/Group.java b/opengl/java/android/opengl/Group.java deleted file mode 100644 index 1ef2953..0000000 --- a/opengl/java/android/opengl/Group.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ShortBuffer; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; -import javax.microedition.khronos.opengles.*; - -class MaterialIndices { - - private Material material = null; - private ShortBuffer indexBuffer = null; - - public MaterialIndices(Material material, ShortBuffer indexBuffer) { - this.material = material; - this.indexBuffer = indexBuffer; - } - - public Material getMaterial() { - return material; - } - - public ShortBuffer getIndexBuffer() { - return indexBuffer; - } -} - -/** - * {@hide} - */ -public class Group { - - private Object3D parent; - private String name; - - private List<MaterialIndices> materialIndices = - new ArrayList<MaterialIndices>(); - - public Group(Object3D parent) { - this.parent = parent; - } - - public String getName() { - return name; - } - - public void load(DataInputStream dis) throws IOException { - dis.readInt(); // name length - this.name = dis.readUTF(); - - int numMaterials = dis.readInt(); - - for (int i = 0; i < numMaterials; i++) { - dis.readInt(); // material name length - String matName = dis.readUTF(); - Material material = parent.getMaterial(matName); - - int numIndices = dis.readInt(); - byte[] indicesBytes = new byte[numIndices * 2]; - dis.readFully(indicesBytes); - - // Swap bytes from network to native order if necessary - if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { - int idx = 0; - for (int j = 0; j < numIndices; j++) { - byte b0 = indicesBytes[idx]; - byte b1 = indicesBytes[idx + 1]; - indicesBytes[idx] = b1; - indicesBytes[idx + 1] = b0; - idx += 2; - } - } - - ByteBuffer ibb = ByteBuffer.allocateDirect(2*numIndices); - ibb.order(ByteOrder.nativeOrder()); - ibb.put(indicesBytes); - ibb.position(0); - - ShortBuffer sb = ibb.asShortBuffer(); - materialIndices.add(new MaterialIndices(material, sb)); - } - } - - public int getNumTriangles() { - int numTriangles = 0; - Iterator<MaterialIndices> iter = materialIndices.iterator(); - while (iter.hasNext()) { - MaterialIndices matIdx = iter.next(); - ShortBuffer indexBuffer = matIdx.getIndexBuffer(); - numTriangles += indexBuffer.capacity()/3; - } - return numTriangles; - } - - public void draw(GL10 gl) { - gl.glDisableClientState(gl.GL_COLOR_ARRAY); - - gl.glVertexPointer(3, gl.GL_FIXED, 0, parent.getVertexBuffer()); - gl.glEnableClientState(gl.GL_VERTEX_ARRAY); - - gl.glNormalPointer(gl.GL_FIXED, 0, parent.getNormalBuffer()); - gl.glEnableClientState(gl.GL_NORMAL_ARRAY); - - if (parent.hasTexcoords()) { - gl.glTexCoordPointer(2, gl.GL_FIXED, 0, parent.getTexcoordBuffer()); - gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY); - gl.glEnable(gl.GL_TEXTURE_2D); - } else { - gl.glDisable(gl.GL_TEXTURE_2D); - } - - Iterator<MaterialIndices> iter = materialIndices.iterator(); - while (iter.hasNext()) { - MaterialIndices matIdx = iter.next(); - ShortBuffer indexBuffer = matIdx.getIndexBuffer(); - Material mat = matIdx.getMaterial(); - mat.setMaterialParameters(gl); - if (parent.hasTexcoords() && mat.getMap_Kd().length() > 0) { - Texture texture = parent.getTexture(mat.getMap_Kd()); - texture.setTextureParameters(gl); - } - - gl.glDrawElements(gl.GL_TRIANGLES, - indexBuffer.capacity(), - gl.GL_UNSIGNED_SHORT, - indexBuffer); - } - } - - public String toString() { - return "Group[" + - "name=" + name + - "]"; - } -} diff --git a/opengl/java/android/opengl/Material.java b/opengl/java/android/opengl/Material.java deleted file mode 100644 index 60a3e72..0000000 --- a/opengl/java/android/opengl/Material.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.io.DataInputStream; -import java.io.IOException; -import javax.microedition.khronos.opengles.GL10; - -/** - * {@hide} - */ -public class Material { - - private Object3D parent; - private String name; - private String map_kd; - private float[] ka = new float[4]; - private float[] kd = new float[4]; - private float[] ks = new float[4]; - private float ns; - private int illum; - private float d; - - private static float[] black = { 0.0f, 0.0f, 0.0f, 1.0f }; - - public Material(Object3D parent) { - this.parent = parent; - } - - public String getName() { - return name; - } - - public String getMap_Kd() { - return map_kd; - } - - public void setMaterialParameters(GL10 gl) { - gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0); - gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0); - gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0); - gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS, - Math.min(Math.max(ns, 0), 128)); - -// if (illum == 0) { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0); -// } else { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, ka, 0); -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0); -// } - -// if (illum > 1) { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0); -// gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS, -// Math.min(Math.max(ns, 0), 128)); -// } else { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, black, 0); -// } - } - - public void load(DataInputStream dis) throws IOException { - dis.readInt(); // name length - this.name = dis.readUTF(); - - dis.readInt(); // map_kdLength - this.map_kd = dis.readUTF(); - - if (parent.hasTexcoords() && map_kd.length() > 0) { - parent.loadTexture(map_kd); - } - - this.ka[0] = dis.readFloat(); - this.ka[1] = dis.readFloat(); - this.ka[2] = dis.readFloat(); - this.ka[3] = dis.readFloat(); - - this.kd[0] = dis.readFloat(); - this.kd[1] = dis.readFloat(); - this.kd[2] = dis.readFloat(); - this.kd[3] = dis.readFloat(); - - this.ks[0] = dis.readFloat(); - this.ks[1] = dis.readFloat(); - this.ks[2] = dis.readFloat(); - this.ks[3] = dis.readFloat(); - - this.ns = dis.readFloat(); - this.illum = dis.readInt(); - this.d = dis.readFloat(); - } - - public String toString() { - return "Material[" + - "name=\"" + name + "\"," + - "ka={" + ka[0] + "," + ka[1] + "," + ka[2] + "}," + - "kd={" + kd[0] + "," + kd[1] + "," + kd[2] + "}," + - "ks={" + ks[0] + "," + ks[1] + "," + ks[2] + "}," + - "ns=" + ns + "," + - "map_kd=\"" + - (map_kd == null ? "" : map_kd) + - "\"," + - "illum=" + illum + "," + - "d=" + d + - "]"; - } -} diff --git a/opengl/java/android/opengl/Object3D.java b/opengl/java/android/opengl/Object3D.java deleted file mode 100644 index 340c6a7..0000000 --- a/opengl/java/android/opengl/Object3D.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import javax.microedition.khronos.opengles.*; - -/** - * {@hide} - */ -public abstract class Object3D { - - private boolean mHasTexcoords = false; - - private float mBoundsMinX = Float.MAX_VALUE; - private float mBoundsMaxX = Float.MIN_VALUE; - private float mBoundsMinY = Float.MAX_VALUE; - private float mBoundsMaxY = Float.MIN_VALUE; - private float mBoundsMinZ = Float.MAX_VALUE; - private float mBoundsMaxZ = Float.MIN_VALUE; - - private IntBuffer mVertexBuffer; - private IntBuffer mNormalBuffer; - private IntBuffer mTexcoordBuffer; - - // All groups, by name - private Map<String, Group> mGroups; - - // All materials, by name - private Map<String, Material> mMaterials; - - // All texture maps, by name - private Map<String, Texture> mTextures; - - public Object3D() { - reset(); - } - - /** - * Override this method with an implementation that contructs - * and InputStream from the given filename. For example, if the - * source files are to be retrieved using an AssetManager, - * the implementation would use AssetManager.load() to - * get the input stream. - */ - public abstract InputStream readFile(String filename) throws IOException; - - private void reset() { - mVertexBuffer = mNormalBuffer = mTexcoordBuffer = null; - - mGroups = new HashMap<String,Group>(); - mMaterials = new HashMap<String,Material>(); - mTextures = new HashMap<String,Texture>(); - } - - public Material getMaterial(String name) { - Material mat = mMaterials.get(name); - return mat; - } - - public Texture getTexture(String name) { - return mTextures.get(name); - } - - public IntBuffer getVertexBuffer() { - return mVertexBuffer; - } - - public IntBuffer getNormalBuffer() { - return mNormalBuffer; - } - - public IntBuffer getTexcoordBuffer() { - return mTexcoordBuffer; - } - - public int getNumTriangles() { - int numTriangles = 0; - Iterator<Group> iter = mGroups.values().iterator(); - while (iter.hasNext()) { - numTriangles += iter.next().getNumTriangles(); - } - return numTriangles; - } - - public boolean hasTexcoords() { - return mHasTexcoords; - } - - public float getBoundsMinX() { - return mBoundsMinX; - } - - public float getBoundsMaxX() { - return mBoundsMaxX; - } - - public float getBoundsMinY() { - return mBoundsMinY; - } - - public float getBoundsMaxY() { - return mBoundsMaxY; - } - - public float getBoundsMinZ() { - return mBoundsMinZ; - } - - public float getBoundsMaxZ() { - return mBoundsMaxZ; - } - - public void loadTexture(String name) throws IOException { - InputStream is = readFile(name + ".raw"); - Texture texture = new Texture(is); - mTextures.put(name, texture); - } - - private static void verifyByte(DataInputStream dis, int b) - throws IOException { - int x = dis.read() & 0xff; - if (x != b) { - throw new RuntimeException("Bad byte: " + - x + - " (expected " + b + ")"); - } - } - - public void load(String filename) throws IOException { - reset(); - - DataInputStream dis = new DataInputStream(readFile(filename)); - verifyByte(dis, 'g' + 128); - verifyByte(dis, 'l'); - verifyByte(dis, 'e'); - verifyByte(dis, 's'); - - int numTuples = dis.readInt(); - - this.mBoundsMinX = dis.readFloat(); - this.mBoundsMaxX = dis.readFloat(); - this.mBoundsMinY = dis.readFloat(); - this.mBoundsMaxY = dis.readFloat(); - this.mBoundsMinZ = dis.readFloat(); - this.mBoundsMaxZ = dis.readFloat(); - - this.mHasTexcoords = dis.readInt() == 1; - - int intsPerTuple = mHasTexcoords ? 8 : 6; - int numInts = numTuples*intsPerTuple; - - int len = 4*numTuples*(mHasTexcoords ? 8 : 6); - - byte[] tmp = new byte[len]; - int tidx = 0; - while (tidx < len) { - tidx += dis.read(tmp, tidx, len - tidx); - } - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { - for (int i = 0; i < len; i += 4) { - byte tmp0 = tmp[i]; - byte tmp1 = tmp[i + 1]; - byte tmp2 = tmp[i + 2]; - byte tmp3 = tmp[i + 3]; - tmp[i] = tmp3; - tmp[i + 1] = tmp2; - tmp[i + 2] = tmp1; - tmp[i + 3] = tmp0; - } - } - - ByteBuffer allbb = ByteBuffer.allocateDirect(len); - allbb.order(ByteOrder.nativeOrder()); - allbb.put(tmp); - - allbb.position(0); - allbb.limit(4*3*numTuples); - ByteBuffer vbb = allbb.slice(); - this.mVertexBuffer = vbb.asIntBuffer(); - mVertexBuffer.position(0); - - if (mHasTexcoords) { - allbb.position(allbb.limit()); - allbb.limit(allbb.position() + 4*2*numTuples); - ByteBuffer tbb = allbb.slice(); - this.mTexcoordBuffer = tbb.asIntBuffer(); - mTexcoordBuffer.position(0); - } - - allbb.position(allbb.limit()); - allbb.limit(allbb.position() + 4*3*numTuples); - ByteBuffer nbb = allbb.slice(); - this.mNormalBuffer = nbb.asIntBuffer(); - mNormalBuffer.position(0); - - int numMaterials = dis.readInt(); - for (int i = 0; i < numMaterials; i++) { - Material mat = new Material(this); - mat.load(dis); - mMaterials.put(mat.getName(), mat); - } - - int numGroups = dis.readInt(); - for (int i = 0; i < numGroups; i++) { - Group g = new Group(this); - g.load(dis); - mGroups.put(g.getName(), g); - } - } - - public void draw(GL10 gl) { - Iterator<Group> iter = mGroups.values().iterator(); - while (iter.hasNext()) { - iter.next().draw(gl); - } - } -} - diff --git a/opengl/java/android/opengl/Texture.java b/opengl/java/android/opengl/Texture.java deleted file mode 100644 index dcd894d..0000000 --- a/opengl/java/android/opengl/Texture.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.io.InputStream; -import java.io.IOException; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import javax.microedition.khronos.opengles.GL10; - -import android.content.res.AssetManager; - -/** - * {@hide} - */ -public class Texture { - - private int width, height, bpp; - private ByteBuffer data; - private int name = -1; - - // Texture maps have the following format. All integers - // are 16 bits, high byte first. Pixels are in 5/6/5 - // RGB format, low byte first. - // - // width - // height - // pixel (0, 0) - // pixel (1, 0) - // ... - // pixel (width - 1, height - 1) - - private int readInt16(InputStream is) throws IOException { - return is.read() | (is.read() << 8); - } - - public Texture(InputStream is) throws IOException { - this.width = readInt16(is); - this.height = readInt16(is); - this.bpp = 2; - - int npixels = width*height; - int nbytes = npixels*bpp; - byte[] arr = new byte[nbytes]; - - int idx = 0; - while (idx < nbytes) { - int nread = is.read(arr, idx, nbytes - idx); - idx += nread; - } - - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { - // Swap pairs of bytes on big-endian platforms - for (int i = 0; i < npixels; i++) { - int j = i*2; - int k = j + 1; - - byte tmp = arr[j]; - arr[j] = arr[k]; - arr[k] = tmp; - } - } - - this.data = ByteBuffer.allocateDirect(arr.length); - this.data.order(ByteOrder.nativeOrder()); - data.put(arr); - data.position(0); - } - - private int loadTexture(GL10 gl, - int textureUnit, - int minFilter, int magFilter, - int wrapS, int wrapT, - int mode, - int width, int height, - int dataType, - Buffer data) { - int[] texture = new int[1]; - gl.glGenTextures(1, texture, 0); - - gl.glEnable(gl.GL_TEXTURE_2D); - gl.glClientActiveTexture(textureUnit); - gl.glBindTexture(gl.GL_TEXTURE_2D, texture[0]); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_MIN_FILTER, - minFilter); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_MAG_FILTER, - magFilter); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_WRAP_S, - wrapS); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_WRAP_T, - wrapT); - gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, mode); - - gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, - width, height, - 0, gl.GL_RGB, dataType, - data); - - return texture[0]; - } - - public void setTextureParameters(GL10 gl) { - if (name < 0) { - name = loadTexture(gl, - gl.GL_TEXTURE0, - gl.GL_NEAREST, gl.GL_NEAREST, - gl.GL_REPEAT, gl.GL_REPEAT, - gl.GL_MODULATE, - width, height, - gl.GL_UNSIGNED_SHORT_5_6_5, - data); - } - - gl.glBindTexture(gl.GL_TEXTURE_2D, name); - } -} |
