summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2013-11-11 17:38:18 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-11-11 17:38:18 +0000
commite77a040f3adcdbfc8fea265126c2d27f73c01243 (patch)
treea754e49395eb9af719540f8dfcdf83c0a9cf5b74
parent2ee011a3c4debc410cbc3f61a3de44616cc32496 (diff)
parent3083579424785e55ca8f82856a6553ee983c3ffb (diff)
downloadframeworks_base-e77a040f3adcdbfc8fea265126c2d27f73c01243.zip
frameworks_base-e77a040f3adcdbfc8fea265126c2d27f73c01243.tar.gz
frameworks_base-e77a040f3adcdbfc8fea265126c2d27f73c01243.tar.bz2
Merge "More refactoring"
-rw-r--r--core/java/android/view/DisplayList.java19
-rw-r--r--core/java/android/view/GLRenderer.java1610
-rw-r--r--core/java/android/view/HardwareRenderer.java1650
-rw-r--r--core/java/android/view/View.java14
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/jni/Android.mk2
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android_view_GLRenderer.cpp (renamed from core/jni/android_view_HardwareRenderer.cpp)32
8 files changed, 1645 insertions, 1688 deletions
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 54fb6ef..623472a 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -86,18 +86,15 @@ import android.graphics.Matrix;
*
* <pre class="prettyprint">
* private void createDisplayList() {
- * HardwareRenderer renderer = getHardwareRenderer();
- * if (renderer != null) {
- * mDisplayList = renderer.createDisplayList();
- * HardwareCanvas canvas = mDisplayList.start(width, height);
- * try {
- * for (Bitmap b : mBitmaps) {
- * canvas.drawBitmap(b, 0.0f, 0.0f, null);
- * canvas.translate(0.0f, b.getHeight());
- * }
- * } finally {
- * displayList.end();
+ * mDisplayList = DisplayList.create("MyDisplayList");
+ * HardwareCanvas canvas = mDisplayList.start(width, height);
+ * try {
+ * for (Bitmap b : mBitmaps) {
+ * canvas.drawBitmap(b, 0.0f, 0.0f, null);
+ * canvas.translate(0.0f, b.getHeight());
* }
+ * } finally {
+ * displayList.end();
* }
* }
*
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
new file mode 100644
index 0000000..a195231
--- /dev/null
+++ b/core/java/android/view/GLRenderer.java
@@ -0,0 +1,1610 @@
+/*
+ * Copyright (C) 2013 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.view;
+
+import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_BAD_NATIVE_WINDOW;
+import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_CONFIG_CAVEAT;
+import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
+import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_DRAW;
+import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT;
+import static javax.microedition.khronos.egl.EGL10.EGL_NONE;
+import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
+import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY;
+import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLES;
+import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLE_BUFFERS;
+import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_SUCCESS;
+import static javax.microedition.khronos.egl.EGL10.EGL_SURFACE_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH;
+import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;
+
+import android.content.ComponentCallbacks2;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.opengl.EGL14;
+import android.opengl.GLUtils;
+import android.opengl.ManagedEGLContext;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Surface.OutOfResourcesException;
+
+import com.google.android.gles_jni.EGLImpl;
+
+import java.io.PrintWriter;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+
+/**
+ * Hardware renderer using OpenGL
+ *
+ * @hide
+ */
+public class GLRenderer extends HardwareRenderer {
+ static final int SURFACE_STATE_ERROR = 0;
+ static final int SURFACE_STATE_SUCCESS = 1;
+ static final int SURFACE_STATE_UPDATED = 2;
+
+ static final int FUNCTOR_PROCESS_DELAY = 4;
+
+ /**
+ * Number of frames to profile.
+ */
+ private static final int PROFILE_MAX_FRAMES = 128;
+
+ /**
+ * Number of floats per profiled frame.
+ */
+ private static final int PROFILE_FRAME_DATA_COUNT = 3;
+
+ private static final int PROFILE_DRAW_MARGIN = 0;
+ private static final int PROFILE_DRAW_WIDTH = 3;
+ private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
+ private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
+ private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
+ private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
+ private static final int PROFILE_DRAW_DP_PER_MS = 7;
+
+ private static final String[] VISUALIZERS = {
+ PROFILE_PROPERTY_VISUALIZE_BARS,
+ PROFILE_PROPERTY_VISUALIZE_LINES
+ };
+
+ private static final String[] OVERDRAW = {
+ OVERDRAW_PROPERTY_SHOW,
+ OVERDRAW_PROPERTY_COUNT
+ };
+ private static final int OVERDRAW_TYPE_COUNT = 1;
+ private static final int GL_VERSION = 2;
+
+ static EGL10 sEgl;
+ static EGLDisplay sEglDisplay;
+ static EGLConfig sEglConfig;
+ static final Object[] sEglLock = new Object[0];
+ int mWidth = -1, mHeight = -1;
+
+ static final ThreadLocal<ManagedEGLContext> sEglContextStorage
+ = new ThreadLocal<ManagedEGLContext>();
+
+ EGLContext mEglContext;
+ Thread mEglThread;
+
+ EGLSurface mEglSurface;
+
+ GL mGl;
+ HardwareCanvas mCanvas;
+
+ String mName;
+
+ long mFrameCount;
+ Paint mDebugPaint;
+
+ static boolean sDirtyRegions;
+ static final boolean sDirtyRegionsRequested;
+ static {
+ String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ sDirtyRegions = "true".equalsIgnoreCase(dirtyProperty);
+ sDirtyRegionsRequested = sDirtyRegions;
+ }
+
+ boolean mDirtyRegionsEnabled;
+ boolean mUpdateDirtyRegions;
+
+ boolean mProfileEnabled;
+ int mProfileVisualizerType = -1;
+ float[] mProfileData;
+ ReentrantLock mProfileLock;
+ int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+
+ GraphDataProvider mDebugDataProvider;
+ float[][] mProfileShapes;
+ Paint mProfilePaint;
+
+ boolean mDebugDirtyRegions;
+ int mDebugOverdraw = -1;
+ HardwareLayer mDebugOverdrawLayer;
+ Paint mDebugOverdrawPaint;
+
+ final boolean mTranslucent;
+
+ private boolean mDestroyed;
+
+ private final Rect mRedrawClip = new Rect();
+
+ private final int[] mSurfaceSize = new int[2];
+ private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
+
+ private long mDrawDelta = Long.MAX_VALUE;
+
+ private GLES20Canvas mGlCanvas;
+
+ private DisplayMetrics mDisplayMetrics;
+
+ private static EGLSurface sPbuffer;
+ private static final Object[] sPbufferLock = new Object[0];
+
+ private static class GLRendererEglContext extends ManagedEGLContext {
+ final Handler mHandler = new Handler();
+
+ public GLRendererEglContext(EGLContext context) {
+ super(context);
+ }
+
+ @Override
+ public void onTerminate(final EGLContext eglContext) {
+ // Make sure we do this on the correct thread.
+ if (mHandler.getLooper() != Looper.myLooper()) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onTerminate(eglContext);
+ }
+ });
+ return;
+ }
+
+ synchronized (sEglLock) {
+ if (sEgl == null) return;
+
+ if (EGLImpl.getInitCount(sEglDisplay) == 1) {
+ usePbufferSurface(eglContext);
+ GLES20Canvas.terminateCaches();
+
+ sEgl.eglDestroyContext(sEglDisplay, eglContext);
+ sEglContextStorage.set(null);
+ sEglContextStorage.remove();
+
+ sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ sEgl.eglReleaseThread();
+ sEgl.eglTerminate(sEglDisplay);
+
+ sEgl = null;
+ sEglDisplay = null;
+ sEglConfig = null;
+ sPbuffer = null;
+ }
+ }
+ }
+ }
+
+ HardwareCanvas createCanvas() {
+ return mGlCanvas = new GLES20Canvas(mTranslucent);
+ }
+
+ ManagedEGLContext createManagedContext(EGLContext eglContext) {
+ return new GLRendererEglContext(mEglContext);
+ }
+
+ int[] getConfig(boolean dirtyRegions) {
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ final int stencilSize = GLES20Canvas.getStencilSize();
+ final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+
+ return new int[] {
+ EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 0,
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_STENCIL_SIZE, stencilSize,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
+ EGL_NONE
+ };
+ }
+
+ void initCaches() {
+ if (GLES20Canvas.initCaches()) {
+ // Caches were (re)initialized, rebind atlas
+ initAtlas();
+ }
+ }
+
+ void initAtlas() {
+ IBinder binder = ServiceManager.getService("assetatlas");
+ if (binder == null) return;
+
+ IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+ try {
+ if (atlas.isCompatible(android.os.Process.myPpid())) {
+ GraphicBuffer buffer = atlas.getBuffer();
+ if (buffer != null) {
+ int[] map = atlas.getMap();
+ if (map != null) {
+ GLES20Canvas.initAtlas(buffer, map);
+ }
+ // If IAssetAtlas is not the same class as the IBinder
+ // we are using a remote service and we can safely
+ // destroy the graphic buffer
+ if (atlas.getClass() != binder.getClass()) {
+ buffer.destroy();
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Could not acquire atlas", e);
+ }
+ }
+
+ boolean canDraw() {
+ return mGl != null && mCanvas != null && mGlCanvas != null;
+ }
+
+ int onPreDraw(Rect dirty) {
+ return mGlCanvas.onPreDraw(dirty);
+ }
+
+ void onPostDraw() {
+ mGlCanvas.onPostDraw();
+ }
+
+ void drawProfileData(View.AttachInfo attachInfo) {
+ if (mDebugDataProvider != null) {
+ final GraphDataProvider provider = mDebugDataProvider;
+ initProfileDrawData(attachInfo, provider);
+
+ final int height = provider.getVerticalUnitSize();
+ final int margin = provider.getHorizontaUnitMargin();
+ final int width = provider.getHorizontalUnitSize();
+
+ int x = 0;
+ int count = 0;
+ int current = 0;
+
+ final float[] data = provider.getData();
+ final int elementCount = provider.getElementCount();
+ final int graphType = provider.getGraphType();
+
+ int totalCount = provider.getFrameCount() * elementCount;
+ if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
+ totalCount -= elementCount;
+ }
+
+ for (int i = 0; i < totalCount; i += elementCount) {
+ if (data[i] < 0.0f) break;
+
+ int index = count * 4;
+ if (i == provider.getCurrentFrame() * elementCount) current = index;
+
+ x += margin;
+ int x2 = x + width;
+
+ int y2 = mHeight;
+ int y1 = (int) (y2 - data[i] * height);
+
+ switch (graphType) {
+ case GraphDataProvider.GRAPH_TYPE_BARS: {
+ for (int j = 0; j < elementCount; j++) {
+ //noinspection MismatchedReadAndWriteOfArray
+ final float[] r = mProfileShapes[j];
+ r[index] = x;
+ r[index + 1] = y1;
+ r[index + 2] = x2;
+ r[index + 3] = y2;
+
+ y2 = y1;
+ if (j < elementCount - 1) {
+ y1 = (int) (y2 - data[i + j + 1] * height);
+ }
+ }
+ } break;
+ case GraphDataProvider.GRAPH_TYPE_LINES: {
+ for (int j = 0; j < elementCount; j++) {
+ //noinspection MismatchedReadAndWriteOfArray
+ final float[] r = mProfileShapes[j];
+ r[index] = (x + x2) * 0.5f;
+ r[index + 1] = index == 0 ? y1 : r[index - 1];
+ r[index + 2] = r[index] + width;
+ r[index + 3] = y1;
+
+ y2 = y1;
+ if (j < elementCount - 1) {
+ y1 = (int) (y2 - data[i + j + 1] * height);
+ }
+ }
+ } break;
+ }
+
+
+ x += width;
+ count++;
+ }
+
+ x += margin;
+
+ drawGraph(graphType, count);
+ drawCurrentFrame(graphType, current);
+ drawThreshold(x, height);
+ }
+ }
+
+ private void drawGraph(int graphType, int count) {
+ for (int i = 0; i < mProfileShapes.length; i++) {
+ mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
+ switch (graphType) {
+ case GraphDataProvider.GRAPH_TYPE_BARS:
+ mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
+ break;
+ case GraphDataProvider.GRAPH_TYPE_LINES:
+ mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
+ break;
+ }
+ }
+ }
+
+ private void drawCurrentFrame(int graphType, int index) {
+ if (index >= 0) {
+ mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
+ switch (graphType) {
+ case GraphDataProvider.GRAPH_TYPE_BARS:
+ mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
+ mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
+ mProfilePaint);
+ break;
+ case GraphDataProvider.GRAPH_TYPE_LINES:
+ mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
+ mProfileShapes[2][index], mHeight, mProfilePaint);
+ break;
+ }
+ }
+ }
+
+ private void drawThreshold(int x, int height) {
+ float threshold = mDebugDataProvider.getThreshold();
+ if (threshold > 0.0f) {
+ mDebugDataProvider.setupThresholdPaint(mProfilePaint);
+ int y = (int) (mHeight - threshold * height);
+ mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
+ }
+ }
+
+ private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
+ if (mProfileShapes == null) {
+ final int elementCount = provider.getElementCount();
+ final int frameCount = provider.getFrameCount();
+
+ mProfileShapes = new float[elementCount][];
+ for (int i = 0; i < elementCount; i++) {
+ mProfileShapes[i] = new float[frameCount * 4];
+ }
+
+ mProfilePaint = new Paint();
+ }
+
+ mProfilePaint.reset();
+ if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
+ mProfilePaint.setAntiAlias(true);
+ }
+
+ if (mDisplayMetrics == null) {
+ mDisplayMetrics = new DisplayMetrics();
+ }
+
+ attachInfo.mDisplay.getMetrics(mDisplayMetrics);
+ provider.prepare(mDisplayMetrics);
+ }
+
+ @Override
+ void destroy(boolean full) {
+ try {
+ if (full && mCanvas != null) {
+ mCanvas = null;
+ }
+
+ if (!isEnabled() || mDestroyed) {
+ setEnabled(false);
+ return;
+ }
+
+ destroySurface();
+ setEnabled(false);
+
+ mDestroyed = true;
+ mGl = null;
+ } finally {
+ if (full && mGlCanvas != null) {
+ mGlCanvas = null;
+ }
+ }
+ }
+
+ @Override
+ void pushLayerUpdate(HardwareLayer layer) {
+ mGlCanvas.pushLayerUpdate(layer);
+ }
+
+ @Override
+ void cancelLayerUpdate(HardwareLayer layer) {
+ mGlCanvas.cancelLayerUpdate(layer);
+ }
+
+ @Override
+ void flushLayerUpdates() {
+ mGlCanvas.flushLayerUpdates();
+ }
+
+ @Override
+ HardwareLayer createHardwareLayer(boolean isOpaque) {
+ return new GLES20TextureLayer(isOpaque);
+ }
+
+ @Override
+ public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
+ return new GLES20RenderLayer(width, height, isOpaque);
+ }
+
+ void countOverdraw(HardwareCanvas canvas) {
+ ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
+ }
+
+ float getOverdraw(HardwareCanvas canvas) {
+ return ((GLES20Canvas) canvas).getOverdraw();
+ }
+
+ @Override
+ public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
+ return ((GLES20TextureLayer) layer).getSurfaceTexture();
+ }
+
+ @Override
+ void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
+ ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
+ }
+
+ @Override
+ boolean safelyRun(Runnable action) {
+ boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
+
+ if (needsContext) {
+ GLRendererEglContext managedContext =
+ (GLRendererEglContext) sEglContextStorage.get();
+ if (managedContext == null) return false;
+ usePbufferSurface(managedContext.getContext());
+ }
+
+ try {
+ action.run();
+ } finally {
+ if (needsContext) {
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ void destroyLayers(final View view) {
+ if (view != null) {
+ safelyRun(new Runnable() {
+ @Override
+ public void run() {
+ if (mCanvas != null) {
+ mCanvas.clearLayerUpdates();
+ }
+ destroyHardwareLayer(view);
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+ }
+ });
+ }
+ }
+
+ private static void destroyHardwareLayer(View view) {
+ view.destroyLayer(true);
+
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+
+ int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ destroyHardwareLayer(group.getChildAt(i));
+ }
+ }
+ }
+
+ @Override
+ void destroyHardwareResources(final View view) {
+ if (view != null) {
+ safelyRun(new Runnable() {
+ @Override
+ public void run() {
+ if (mCanvas != null) {
+ mCanvas.clearLayerUpdates();
+ }
+ destroyResources(view);
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+ }
+ });
+ }
+ }
+
+ private static void destroyResources(View view) {
+ view.destroyHardwareResources();
+
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+
+ int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ destroyResources(group.getChildAt(i));
+ }
+ }
+ }
+
+ static void startTrimMemory(int level) {
+ if (sEgl == null || sEglConfig == null) return;
+
+ GLRendererEglContext managedContext =
+ (GLRendererEglContext) sEglContextStorage.get();
+ // We do not have OpenGL objects
+ if (managedContext == null) {
+ return;
+ } else {
+ usePbufferSurface(managedContext.getContext());
+ }
+
+ if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
+ } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
+ }
+ }
+
+ static void endTrimMemory() {
+ if (sEgl != null && sEglDisplay != null) {
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+ }
+
+ private static void usePbufferSurface(EGLContext eglContext) {
+ synchronized (sPbufferLock) {
+ // Create a temporary 1x1 pbuffer so we have a context
+ // to clear our OpenGL objects
+ if (sPbuffer == null) {
+ sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
+ EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
+ });
+ }
+ }
+ sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ }
+
+ GLRenderer(boolean translucent) {
+ mTranslucent = translucent;
+
+ loadSystemProperties(null);
+ }
+
+ @Override
+ boolean loadSystemProperties(Surface surface) {
+ boolean value;
+ boolean changed = false;
+
+ String profiling = SystemProperties.get(PROFILE_PROPERTY);
+ int graphType = search(VISUALIZERS, profiling);
+ value = graphType >= 0;
+
+ if (graphType != mProfileVisualizerType) {
+ changed = true;
+ mProfileVisualizerType = graphType;
+
+ mProfileShapes = null;
+ mProfilePaint = null;
+
+ if (value) {
+ mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
+ } else {
+ mDebugDataProvider = null;
+ }
+ }
+
+ // If on-screen profiling is not enabled, we need to check whether
+ // console profiling only is enabled
+ if (!value) {
+ value = Boolean.parseBoolean(profiling);
+ }
+
+ if (value != mProfileEnabled) {
+ changed = true;
+ mProfileEnabled = value;
+
+ if (mProfileEnabled) {
+ Log.d(LOG_TAG, "Profiling hardware renderer");
+
+ int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
+ PROFILE_MAX_FRAMES);
+ mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
+ for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
+ }
+
+ mProfileLock = new ReentrantLock();
+ } else {
+ mProfileData = null;
+ mProfileLock = null;
+ mProfileVisualizerType = -1;
+ }
+
+ mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+ }
+
+ value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
+ if (value != mDebugDirtyRegions) {
+ changed = true;
+ mDebugDirtyRegions = value;
+
+ if (mDebugDirtyRegions) {
+ Log.d(LOG_TAG, "Debugging dirty regions");
+ }
+ }
+
+ String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
+ int debugOverdraw = search(OVERDRAW, overdraw);
+ if (debugOverdraw != mDebugOverdraw) {
+ changed = true;
+ mDebugOverdraw = debugOverdraw;
+
+ if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
+ if (mDebugOverdrawLayer != null) {
+ mDebugOverdrawLayer.destroy();
+ mDebugOverdrawLayer = null;
+ mDebugOverdrawPaint = null;
+ }
+ }
+ }
+
+ if (loadProperties()) {
+ changed = true;
+ }
+
+ return changed;
+ }
+
+ private static int search(String[] values, String value) {
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].equals(value)) return i;
+ }
+ return -1;
+ }
+
+ @Override
+ void dumpGfxInfo(PrintWriter pw) {
+ if (mProfileEnabled) {
+ pw.printf("\n\tDraw\tProcess\tExecute\n");
+
+ mProfileLock.lock();
+ try {
+ for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ if (mProfileData[i] < 0) {
+ break;
+ }
+ pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+ mProfileData[i + 2]);
+ mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
+ }
+ mProfileCurrentFrame = mProfileData.length;
+ } finally {
+ mProfileLock.unlock();
+ }
+ }
+ }
+
+ @Override
+ long getFrameCount() {
+ return mFrameCount;
+ }
+
+ /**
+ * Indicates whether this renderer instance can track and update dirty regions.
+ */
+ boolean hasDirtyRegions() {
+ return mDirtyRegionsEnabled;
+ }
+
+ /**
+ * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
+ * is invoked and the requested flag is turned off. The error code is
+ * also logged as a warning.
+ */
+ void checkEglErrors() {
+ if (isEnabled()) {
+ checkEglErrorsForced();
+ }
+ }
+
+ private void checkEglErrorsForced() {
+ int error = sEgl.eglGetError();
+ if (error != EGL_SUCCESS) {
+ // something bad has happened revert to
+ // normal rendering.
+ Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
+ fallback(error != EGL11.EGL_CONTEXT_LOST);
+ }
+ }
+
+ private void fallback(boolean fallback) {
+ destroy(true);
+ if (fallback) {
+ // we'll try again if it was context lost
+ setRequested(false);
+ Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
+ + "Switching back to software rendering.");
+ }
+ }
+
+ @Override
+ boolean initialize(Surface surface) throws OutOfResourcesException {
+ if (isRequested() && !isEnabled()) {
+ boolean contextCreated = initializeEgl();
+ mGl = createEglSurface(surface);
+ mDestroyed = false;
+
+ if (mGl != null) {
+ int err = sEgl.eglGetError();
+ if (err != EGL_SUCCESS) {
+ destroy(true);
+ setRequested(false);
+ } else {
+ if (mCanvas == null) {
+ mCanvas = createCanvas();
+ mCanvas.setName(mName);
+ }
+ setEnabled(true);
+
+ if (contextCreated) {
+ initAtlas();
+ }
+ }
+
+ return mCanvas != null;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ void updateSurface(Surface surface) throws OutOfResourcesException {
+ if (isRequested() && isEnabled()) {
+ createEglSurface(surface);
+ }
+ }
+
+ boolean initializeEgl() {
+ synchronized (sEglLock) {
+ if (sEgl == null && sEglConfig == null) {
+ sEgl = (EGL10) EGLContext.getEGL();
+
+ // Get to the default display.
+ sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ if (sEglDisplay == EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed "
+ + GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ }
+
+ // We can now initialize EGL for that display
+ int[] version = new int[2];
+ if (!sEgl.eglInitialize(sEglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed " +
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ }
+
+ checkEglErrorsForced();
+
+ sEglConfig = loadEglConfig();
+ }
+ }
+
+ ManagedEGLContext managedContext = sEglContextStorage.get();
+ mEglContext = managedContext != null ? managedContext.getContext() : null;
+ mEglThread = Thread.currentThread();
+
+ if (mEglContext == null) {
+ mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
+ sEglContextStorage.set(createManagedContext(mEglContext));
+ return true;
+ }
+
+ return false;
+ }
+
+ private EGLConfig loadEglConfig() {
+ EGLConfig eglConfig = chooseEglConfig();
+ if (eglConfig == null) {
+ // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
+ if (sDirtyRegions) {
+ sDirtyRegions = false;
+ eglConfig = chooseEglConfig();
+ if (eglConfig == null) {
+ throw new RuntimeException("eglConfig not initialized");
+ }
+ } else {
+ throw new RuntimeException("eglConfig not initialized");
+ }
+ }
+ return eglConfig;
+ }
+
+ private EGLConfig chooseEglConfig() {
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configsCount = new int[1];
+ int[] configSpec = getConfig(sDirtyRegions);
+
+ // Debug
+ final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
+ if ("all".equalsIgnoreCase(debug)) {
+ sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
+
+ EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
+ sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
+ configsCount[0], configsCount);
+
+ for (EGLConfig config : debugConfigs) {
+ printConfig(config);
+ }
+ }
+
+ if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ if ("choice".equalsIgnoreCase(debug)) {
+ printConfig(configs[0]);
+ }
+ return configs[0];
+ }
+
+ return null;
+ }
+
+ private static void printConfig(EGLConfig config) {
+ int[] value = new int[1];
+
+ Log.d(LOG_TAG, "EGL configuration " + config + ":");
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
+ Log.d(LOG_TAG, " RED_SIZE = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
+ Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
+ Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
+ Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
+ Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
+ Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
+ Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
+ Log.d(LOG_TAG, " SAMPLES = " + value[0]);
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
+ Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
+
+ sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
+ Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
+ }
+
+ GL createEglSurface(Surface surface) throws OutOfResourcesException {
+ // Check preconditions.
+ if (sEgl == null) {
+ throw new RuntimeException("egl not initialized");
+ }
+ if (sEglDisplay == null) {
+ throw new RuntimeException("eglDisplay not initialized");
+ }
+ if (sEglConfig == null) {
+ throw new RuntimeException("eglConfig not initialized");
+ }
+ if (Thread.currentThread() != mEglThread) {
+ throw new IllegalStateException("HardwareRenderer cannot be used "
+ + "from multiple threads");
+ }
+
+ // In case we need to destroy an existing surface
+ destroySurface();
+
+ // Create an EGL surface we can render into.
+ if (!createSurface(surface)) {
+ return null;
+ }
+
+ initCaches();
+
+ return mEglContext.getGL();
+ }
+
+ private void enableDirtyRegions() {
+ // If mDirtyRegions is set, this means we have an EGL configuration
+ // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
+ if (sDirtyRegions) {
+ if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
+ Log.w(LOG_TAG, "Backbuffer cannot be preserved");
+ }
+ } else if (sDirtyRegionsRequested) {
+ // If mDirtyRegions is not set, our EGL configuration does not
+ // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
+ // swap behavior might be EGL_BUFFER_PRESERVED, which means we
+ // want to set mDirtyRegions. We try to do this only if dirty
+ // regions were initially requested as part of the device
+ // configuration (see RENDER_DIRTY_REGIONS)
+ mDirtyRegionsEnabled = isBackBufferPreserved();
+ }
+ }
+
+ EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ final int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, GL_VERSION, EGL_NONE };
+
+ EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
+ attribs);
+ if (context == null || context == EGL_NO_CONTEXT) {
+ //noinspection ConstantConditions
+ throw new IllegalStateException(
+ "Could not create an EGL context. eglCreateContext failed with error: " +
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ }
+
+ return context;
+ }
+
+ void destroySurface() {
+ if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+ if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
+ sEgl.eglMakeCurrent(sEglDisplay,
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ }
+
+ @Override
+ void invalidate(Surface surface) {
+ // Cancels any existing buffer to ensure we'll get a buffer
+ // of the right size before we call eglSwapBuffers
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ mEglSurface = null;
+ setEnabled(false);
+ }
+
+ if (surface.isValid()) {
+ if (!createSurface(surface)) {
+ return;
+ }
+
+ mUpdateDirtyRegions = true;
+
+ if (mCanvas != null) {
+ setEnabled(true);
+ }
+ }
+ }
+
+ private boolean createSurface(Surface surface) {
+ mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
+
+ if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
+ int error = sEgl.eglGetError();
+ if (error == EGL_BAD_NATIVE_WINDOW) {
+ Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ return false;
+ }
+ throw new RuntimeException("createWindowSurface failed "
+ + GLUtils.getEGLErrorString(error));
+ }
+
+ if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new IllegalStateException("eglMakeCurrent failed " +
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ }
+
+ enableDirtyRegions();
+
+ return true;
+ }
+
+ @Override
+ boolean validate() {
+ return checkRenderContext() != SURFACE_STATE_ERROR;
+ }
+
+ @Override
+ void setup(int width, int height) {
+ if (validate()) {
+ mCanvas.setViewport(width, height);
+ mWidth = width;
+ mHeight = height;
+ }
+ }
+
+ @Override
+ int getWidth() {
+ return mWidth;
+ }
+
+ @Override
+ int getHeight() {
+ return mHeight;
+ }
+
+ @Override
+ HardwareCanvas getCanvas() {
+ return mCanvas;
+ }
+
+ @Override
+ void setName(String name) {
+ mName = name;
+ }
+
+ class FunctorsRunnable implements Runnable {
+ View.AttachInfo attachInfo;
+
+ @Override
+ public void run() {
+ final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
+ if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) {
+ return;
+ }
+
+ if (checkRenderContext() != SURFACE_STATE_ERROR) {
+ int status = mCanvas.invokeFunctors(mRedrawClip);
+ handleFunctorStatus(attachInfo, status);
+ }
+ }
+ }
+
+ @Override
+ void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
+ Rect dirty) {
+ if (canDraw()) {
+ if (!hasDirtyRegions()) {
+ dirty = null;
+ }
+ attachInfo.mIgnoreDirtyState = true;
+ attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+
+ view.mPrivateFlags |= View.PFLAG_DRAWN;
+
+ // We are already on the correct thread
+ final int surfaceState = checkRenderContextUnsafe();
+ if (surfaceState != SURFACE_STATE_ERROR) {
+ HardwareCanvas canvas = mCanvas;
+ attachInfo.mHardwareCanvas = canvas;
+
+ if (mProfileEnabled) {
+ mProfileLock.lock();
+ }
+
+ dirty = beginFrame(canvas, dirty, surfaceState);
+
+ DisplayList displayList = buildDisplayList(view, canvas);
+
+ // buildDisplayList() calls into user code which can cause
+ // an eglMakeCurrent to happen with a different surface/context.
+ // We must therefore check again here.
+ if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
+ return;
+ }
+
+ int saveCount = 0;
+ int status = DisplayList.STATUS_DONE;
+
+ long start = getSystemTime();
+ try {
+ status = prepareFrame(dirty);
+
+ saveCount = canvas.save();
+ callbacks.onHardwarePreDraw(canvas);
+
+ if (displayList != null) {
+ status |= drawDisplayList(attachInfo, canvas, displayList, status);
+ } else {
+ // Shouldn't reach here
+ view.draw(canvas);
+ }
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "An error has occurred while drawing:", e);
+ } finally {
+ callbacks.onHardwarePostDraw(canvas);
+ canvas.restoreToCount(saveCount);
+ view.mRecreateDisplayList = false;
+
+ mDrawDelta = getSystemTime() - start;
+
+ if (mDrawDelta > 0) {
+ mFrameCount++;
+
+ debugOverdraw(attachInfo, dirty, canvas, displayList);
+ debugDirtyRegions(dirty, canvas);
+ drawProfileData(attachInfo);
+ }
+ }
+
+ onPostDraw();
+
+ swapBuffers(status);
+
+ if (mProfileEnabled) {
+ mProfileLock.unlock();
+ }
+
+ attachInfo.mIgnoreDirtyState = false;
+ }
+ }
+ }
+
+ private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
+ HardwareCanvas canvas, DisplayList displayList) {
+
+ if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
+ if (mDebugOverdrawLayer == null) {
+ mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
+ } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
+ mDebugOverdrawLayer.getHeight() != mHeight) {
+ mDebugOverdrawLayer.resize(mWidth, mHeight);
+ }
+
+ if (!mDebugOverdrawLayer.isValid()) {
+ mDebugOverdraw = -1;
+ return;
+ }
+
+ HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
+ countOverdraw(layerCanvas);
+ final int restoreCount = layerCanvas.save();
+ layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
+ layerCanvas.restoreToCount(restoreCount);
+ mDebugOverdrawLayer.end(canvas);
+
+ float overdraw = getOverdraw(layerCanvas);
+ DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
+
+ drawOverdrawCounter(canvas, overdraw, metrics.density);
+ }
+ }
+
+ private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
+ final String text = String.format("%.2fx", overdraw);
+ final Paint paint = setupPaint(density);
+ // HSBtoColor will clamp the values in the 0..1 range
+ paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
+
+ canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
+ }
+
+ private Paint setupPaint(float density) {
+ if (mDebugOverdrawPaint == null) {
+ mDebugOverdrawPaint = new Paint();
+ mDebugOverdrawPaint.setAntiAlias(true);
+ mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
+ mDebugOverdrawPaint.setTextSize(density * 20.0f);
+ }
+ return mDebugOverdrawPaint;
+ }
+
+ private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
+ if (mDrawDelta <= 0) {
+ return view.mDisplayList;
+ }
+
+ view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
+ == View.PFLAG_INVALIDATED;
+ view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
+
+ long buildDisplayListStartTime = startBuildDisplayListProfiling();
+ canvas.clearLayerUpdates();
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+ DisplayList displayList = view.getDisplayList();
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+
+ endBuildDisplayListProfiling(buildDisplayListStartTime);
+
+ return displayList;
+ }
+
+ private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
+ // We had to change the current surface and/or context, redraw everything
+ if (surfaceState == SURFACE_STATE_UPDATED) {
+ dirty = null;
+ beginFrame(null);
+ } else {
+ int[] size = mSurfaceSize;
+ beginFrame(size);
+
+ if (size[1] != mHeight || size[0] != mWidth) {
+ mWidth = size[0];
+ mHeight = size[1];
+
+ canvas.setViewport(mWidth, mHeight);
+
+ dirty = null;
+ }
+ }
+
+ if (mDebugDataProvider != null) dirty = null;
+
+ return dirty;
+ }
+
+ private long startBuildDisplayListProfiling() {
+ if (mProfileEnabled) {
+ mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+ if (mProfileCurrentFrame >= mProfileData.length) {
+ mProfileCurrentFrame = 0;
+ }
+
+ return System.nanoTime();
+ }
+ return 0;
+ }
+
+ private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
+ if (mProfileEnabled) {
+ long now = System.nanoTime();
+ float total = (now - getDisplayListStartTime) * 0.000001f;
+ //noinspection PointlessArithmeticExpression
+ mProfileData[mProfileCurrentFrame] = total;
+ }
+ }
+
+ private int prepareFrame(Rect dirty) {
+ int status;
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
+ try {
+ status = onPreDraw(dirty);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return status;
+ }
+
+ private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
+ DisplayList displayList, int status) {
+
+ long drawDisplayListStartTime = 0;
+ if (mProfileEnabled) {
+ drawDisplayListStartTime = System.nanoTime();
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
+ try {
+ status |= canvas.drawDisplayList(displayList, mRedrawClip,
+ DisplayList.FLAG_CLIP_CHILDREN);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
+ if (mProfileEnabled) {
+ long now = System.nanoTime();
+ float total = (now - drawDisplayListStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 1] = total;
+ }
+
+ handleFunctorStatus(attachInfo, status);
+ return status;
+ }
+
+ private void swapBuffers(int status) {
+ if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
+ long eglSwapBuffersStartTime = 0;
+ if (mProfileEnabled) {
+ eglSwapBuffersStartTime = System.nanoTime();
+ }
+
+ sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
+
+ if (mProfileEnabled) {
+ long now = System.nanoTime();
+ float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 2] = total;
+ }
+
+ checkEglErrors();
+ }
+ }
+
+ private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
+ if (mDebugDirtyRegions) {
+ if (mDebugPaint == null) {
+ mDebugPaint = new Paint();
+ mDebugPaint.setColor(0x7fff0000);
+ }
+
+ if (dirty != null && (mFrameCount & 1) == 0) {
+ canvas.drawRect(dirty, mDebugPaint);
+ }
+ }
+ }
+
+ private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
+ // If the draw flag is set, functors will be invoked while executing
+ // the tree of display lists
+ if ((status & DisplayList.STATUS_DRAW) != 0) {
+ if (mRedrawClip.isEmpty()) {
+ attachInfo.mViewRootImpl.invalidate();
+ } else {
+ attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
+ mRedrawClip.setEmpty();
+ }
+ }
+
+ if ((status & DisplayList.STATUS_INVOKE) != 0 ||
+ attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
+ attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+ mFunctorsRunnable.attachInfo = attachInfo;
+ attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
+ }
+ }
+
+ @Override
+ void detachFunctor(int functor) {
+ if (mCanvas != null) {
+ mCanvas.detachFunctor(functor);
+ }
+ }
+
+ @Override
+ boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
+ if (mCanvas != null) {
+ mCanvas.attachFunctor(functor);
+ mFunctorsRunnable.attachInfo = attachInfo;
+ attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+ attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Ensures the current EGL context and surface are the ones we expect.
+ * This method throws an IllegalStateException if invoked from a thread
+ * that did not initialize EGL.
+ *
+ * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
+ * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
+ * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+ *
+ * @see #checkRenderContextUnsafe()
+ */
+ int checkRenderContext() {
+ if (mEglThread != Thread.currentThread()) {
+ throw new IllegalStateException("Hardware acceleration can only be used with a " +
+ "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
+ "Current thread: " + Thread.currentThread());
+ }
+
+ return checkRenderContextUnsafe();
+ }
+
+ /**
+ * Ensures the current EGL context and surface are the ones we expect.
+ * This method does not check the current thread.
+ *
+ * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
+ * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
+ * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+ *
+ * @see #checkRenderContext()
+ */
+ private int checkRenderContextUnsafe() {
+ if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
+ !mEglContext.equals(sEgl.eglGetCurrentContext())) {
+ if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ Log.e(LOG_TAG, "eglMakeCurrent failed " +
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ fallback(true);
+ return SURFACE_STATE_ERROR;
+ } else {
+ if (mUpdateDirtyRegions) {
+ enableDirtyRegions();
+ mUpdateDirtyRegions = false;
+ }
+ return SURFACE_STATE_UPDATED;
+ }
+ }
+ return SURFACE_STATE_SUCCESS;
+ }
+
+ private static int dpToPx(int dp, float density) {
+ return (int) (dp * density + 0.5f);
+ }
+
+ private static native boolean loadProperties();
+
+ static native void setupShadersDiskCache(String cacheFile);
+
+ /**
+ * Notifies EGL that the frame is about to be rendered.
+ * @param size
+ */
+ private static native void beginFrame(int[] size);
+
+ /**
+ * Returns the current system time according to the renderer.
+ * This method is used for debugging only and should not be used
+ * as a clock.
+ */
+ private static native long getSystemTime();
+
+ /**
+ * Preserves the back buffer of the current surface after a buffer swap.
+ * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
+ * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
+ * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
+ *
+ * @return True if the swap behavior was successfully changed,
+ * false otherwise.
+ */
+ private static native boolean preserveBackBuffer();
+
+ /**
+ * Indicates whether the current surface preserves its back buffer
+ * after a buffer swap.
+ *
+ * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
+ * false otherwise
+ */
+ private static native boolean isBackBufferPreserved();
+
+ class DrawPerformanceDataProvider extends GraphDataProvider {
+ private final int mGraphType;
+
+ private int mVerticalUnit;
+ private int mHorizontalUnit;
+ private int mHorizontalMargin;
+ private int mThresholdStroke;
+
+ DrawPerformanceDataProvider(int graphType) {
+ mGraphType = graphType;
+ }
+
+ @Override
+ void prepare(DisplayMetrics metrics) {
+ final float density = metrics.density;
+
+ mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
+ mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
+ mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
+ mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
+ }
+
+ @Override
+ int getGraphType() {
+ return mGraphType;
+ }
+
+ @Override
+ int getVerticalUnitSize() {
+ return mVerticalUnit;
+ }
+
+ @Override
+ int getHorizontalUnitSize() {
+ return mHorizontalUnit;
+ }
+
+ @Override
+ int getHorizontaUnitMargin() {
+ return mHorizontalMargin;
+ }
+
+ @Override
+ float[] getData() {
+ return mProfileData;
+ }
+
+ @Override
+ float getThreshold() {
+ return 16;
+ }
+
+ @Override
+ int getFrameCount() {
+ return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
+ }
+
+ @Override
+ int getElementCount() {
+ return PROFILE_FRAME_DATA_COUNT;
+ }
+
+ @Override
+ int getCurrentFrame() {
+ return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
+ }
+
+ @Override
+ void setupGraphPaint(Paint paint, int elementIndex) {
+ paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
+ if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
+ }
+
+ @Override
+ void setupThresholdPaint(Paint paint) {
+ paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
+ paint.setStrokeWidth(mThresholdStroke);
+ }
+
+ @Override
+ void setupCurrentFramePaint(Paint paint) {
+ paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
+ if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
+ }
+ }
+}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 4ddae19..5c0be4a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -16,41 +16,14 @@
package android.view;
-import android.content.ComponentCallbacks2;
-import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
-import android.opengl.EGL14;
-import android.opengl.GLUtils;
-import android.opengl.ManagedEGLContext;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Trace;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.Surface.OutOfResourcesException;
-import com.google.android.gles_jni.EGLImpl;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL;
-
import java.io.File;
import java.io.PrintWriter;
-import java.util.concurrent.locks.ReentrantLock;
-
-import static javax.microedition.khronos.egl.EGL10.*;
/**
* Interface for rendering a view hierarchy using hardware acceleration.
@@ -215,16 +188,6 @@ public abstract class HardwareRenderer {
*/
public static boolean sSystemRendererDisabled = false;
- /**
- * Number of frames to profile.
- */
- private static final int PROFILE_MAX_FRAMES = 128;
-
- /**
- * Number of floats per profiled frame.
- */
- private static final int PROFILE_FRAME_DATA_COUNT = 3;
-
private boolean mEnabled;
private boolean mRequested = true;
@@ -374,8 +337,6 @@ public abstract class HardwareRenderer {
*/
abstract boolean loadSystemProperties(Surface surface);
- private static native boolean nLoadProperties();
-
/**
* Sets the directory to use as a persistent storage for hardware rendering
* resources.
@@ -385,60 +346,9 @@ public abstract class HardwareRenderer {
* @hide
*/
public static void setupDiskCache(File cacheDir) {
- nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
- }
-
- private static native void nSetupShadersDiskCache(String cacheFile);
-
- /**
- * Notifies EGL that the frame is about to be rendered.
- * @param size
- */
- static void beginFrame(int[] size) {
- nBeginFrame(size);
+ GLRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
}
- private static native void nBeginFrame(int[] size);
-
- /**
- * Returns the current system time according to the renderer.
- * This method is used for debugging only and should not be used
- * as a clock.
- */
- static long getSystemTime() {
- return nGetSystemTime();
- }
-
- private static native long nGetSystemTime();
-
- /**
- * Preserves the back buffer of the current surface after a buffer swap.
- * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
- * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
- * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
- *
- * @return True if the swap behavior was successfully changed,
- * false otherwise.
- */
- static boolean preserveBackBuffer() {
- return nPreserveBackBuffer();
- }
-
- private static native boolean nPreserveBackBuffer();
-
- /**
- * Indicates whether the current surface preserves its back buffer
- * after a buffer swap.
- *
- * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
- * false otherwise
- */
- static boolean isBackBufferPreserved() {
- return nIsBackBufferPreserved();
- }
-
- private static native boolean nIsBackBufferPreserved();
-
/**
* Indicates that the specified hardware layer needs to be updated
* as soon as possible.
@@ -602,17 +512,15 @@ public abstract class HardwareRenderer {
/**
* Creates a hardware renderer using OpenGL.
*
- * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
* @param translucent True if the surface is translucent, false otherwise
*
* @return A hardware renderer backed by OpenGL.
*/
- static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
- switch (glVersion) {
- case 2:
- return Gl20Renderer.create(translucent);
+ static HardwareRenderer create(boolean translucent) {
+ if (GLES20Canvas.isAvailable()) {
+ return new GLRenderer(translucent);
}
- throw new IllegalArgumentException("Unknown GL version: " + glVersion);
+ return null;
}
/**
@@ -637,7 +545,7 @@ public abstract class HardwareRenderer {
* see {@link android.content.ComponentCallbacks}
*/
static void startTrimMemory(int level) {
- Gl20Renderer.startTrimMemory(level);
+ GLRenderer.startTrimMemory(level);
}
/**
@@ -645,7 +553,7 @@ public abstract class HardwareRenderer {
* cleanup special resources used by the memory trimming process.
*/
static void endTrimMemory() {
- Gl20Renderer.endTrimMemory();
+ GLRenderer.endTrimMemory();
}
/**
@@ -779,1548 +687,4 @@ public abstract class HardwareRenderer {
*/
abstract void setupCurrentFramePaint(Paint paint);
}
-
- @SuppressWarnings({"deprecation"})
- static abstract class GlRenderer extends HardwareRenderer {
- static final int SURFACE_STATE_ERROR = 0;
- static final int SURFACE_STATE_SUCCESS = 1;
- static final int SURFACE_STATE_UPDATED = 2;
-
- static final int FUNCTOR_PROCESS_DELAY = 4;
-
- private static final int PROFILE_DRAW_MARGIN = 0;
- private static final int PROFILE_DRAW_WIDTH = 3;
- private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
- private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
- private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
- private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
- private static final int PROFILE_DRAW_DP_PER_MS = 7;
-
- private static final String[] VISUALIZERS = {
- PROFILE_PROPERTY_VISUALIZE_BARS,
- PROFILE_PROPERTY_VISUALIZE_LINES
- };
-
- private static final String[] OVERDRAW = {
- OVERDRAW_PROPERTY_SHOW,
- OVERDRAW_PROPERTY_COUNT
- };
- private static final int OVERDRAW_TYPE_COUNT = 1;
-
- static EGL10 sEgl;
- static EGLDisplay sEglDisplay;
- static EGLConfig sEglConfig;
- static final Object[] sEglLock = new Object[0];
- int mWidth = -1, mHeight = -1;
-
- static final ThreadLocal<ManagedEGLContext> sEglContextStorage
- = new ThreadLocal<ManagedEGLContext>();
-
- EGLContext mEglContext;
- Thread mEglThread;
-
- EGLSurface mEglSurface;
-
- GL mGl;
- HardwareCanvas mCanvas;
-
- String mName;
-
- long mFrameCount;
- Paint mDebugPaint;
-
- static boolean sDirtyRegions;
- static final boolean sDirtyRegionsRequested;
- static {
- String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
- //noinspection PointlessBooleanExpression,ConstantConditions
- sDirtyRegions = "true".equalsIgnoreCase(dirtyProperty);
- sDirtyRegionsRequested = sDirtyRegions;
- }
-
- boolean mDirtyRegionsEnabled;
- boolean mUpdateDirtyRegions;
-
- boolean mProfileEnabled;
- int mProfileVisualizerType = -1;
- float[] mProfileData;
- ReentrantLock mProfileLock;
- int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-
- GraphDataProvider mDebugDataProvider;
- float[][] mProfileShapes;
- Paint mProfilePaint;
-
- boolean mDebugDirtyRegions;
- int mDebugOverdraw = -1;
- HardwareLayer mDebugOverdrawLayer;
- Paint mDebugOverdrawPaint;
-
- final int mGlVersion;
- final boolean mTranslucent;
-
- private boolean mDestroyed;
-
- private final Rect mRedrawClip = new Rect();
-
- private final int[] mSurfaceSize = new int[2];
- private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
-
- private long mDrawDelta = Long.MAX_VALUE;
-
- GlRenderer(int glVersion, boolean translucent) {
- mGlVersion = glVersion;
- mTranslucent = translucent;
-
- loadSystemProperties(null);
- }
-
- @Override
- boolean loadSystemProperties(Surface surface) {
- boolean value;
- boolean changed = false;
-
- String profiling = SystemProperties.get(PROFILE_PROPERTY);
- int graphType = search(VISUALIZERS, profiling);
- value = graphType >= 0;
-
- if (graphType != mProfileVisualizerType) {
- changed = true;
- mProfileVisualizerType = graphType;
-
- mProfileShapes = null;
- mProfilePaint = null;
-
- if (value) {
- mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
- } else {
- mDebugDataProvider = null;
- }
- }
-
- // If on-screen profiling is not enabled, we need to check whether
- // console profiling only is enabled
- if (!value) {
- value = Boolean.parseBoolean(profiling);
- }
-
- if (value != mProfileEnabled) {
- changed = true;
- mProfileEnabled = value;
-
- if (mProfileEnabled) {
- Log.d(LOG_TAG, "Profiling hardware renderer");
-
- int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
- PROFILE_MAX_FRAMES);
- mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
- for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
- mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
- }
-
- mProfileLock = new ReentrantLock();
- } else {
- mProfileData = null;
- mProfileLock = null;
- mProfileVisualizerType = -1;
- }
-
- mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
- }
-
- value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
- if (value != mDebugDirtyRegions) {
- changed = true;
- mDebugDirtyRegions = value;
-
- if (mDebugDirtyRegions) {
- Log.d(LOG_TAG, "Debugging dirty regions");
- }
- }
-
- String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
- int debugOverdraw = search(OVERDRAW, overdraw);
- if (debugOverdraw != mDebugOverdraw) {
- changed = true;
- mDebugOverdraw = debugOverdraw;
-
- if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
- if (mDebugOverdrawLayer != null) {
- mDebugOverdrawLayer.destroy();
- mDebugOverdrawLayer = null;
- mDebugOverdrawPaint = null;
- }
- }
- }
-
- if (nLoadProperties()) {
- changed = true;
- }
-
- return changed;
- }
-
- private static int search(String[] values, String value) {
- for (int i = 0; i < values.length; i++) {
- if (values[i].equals(value)) return i;
- }
- return -1;
- }
-
- @Override
- void dumpGfxInfo(PrintWriter pw) {
- if (mProfileEnabled) {
- pw.printf("\n\tDraw\tProcess\tExecute\n");
-
- mProfileLock.lock();
- try {
- for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
- if (mProfileData[i] < 0) {
- break;
- }
- pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
- mProfileData[i + 2]);
- mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
- }
- mProfileCurrentFrame = mProfileData.length;
- } finally {
- mProfileLock.unlock();
- }
- }
- }
-
- @Override
- long getFrameCount() {
- return mFrameCount;
- }
-
- /**
- * Indicates whether this renderer instance can track and update dirty regions.
- */
- boolean hasDirtyRegions() {
- return mDirtyRegionsEnabled;
- }
-
- /**
- * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
- * is invoked and the requested flag is turned off. The error code is
- * also logged as a warning.
- */
- void checkEglErrors() {
- if (isEnabled()) {
- checkEglErrorsForced();
- }
- }
-
- private void checkEglErrorsForced() {
- int error = sEgl.eglGetError();
- if (error != EGL_SUCCESS) {
- // something bad has happened revert to
- // normal rendering.
- Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
- fallback(error != EGL11.EGL_CONTEXT_LOST);
- }
- }
-
- private void fallback(boolean fallback) {
- destroy(true);
- if (fallback) {
- // we'll try again if it was context lost
- setRequested(false);
- Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
- + "Switching back to software rendering.");
- }
- }
-
- @Override
- boolean initialize(Surface surface) throws OutOfResourcesException {
- if (isRequested() && !isEnabled()) {
- boolean contextCreated = initializeEgl();
- mGl = createEglSurface(surface);
- mDestroyed = false;
-
- if (mGl != null) {
- int err = sEgl.eglGetError();
- if (err != EGL_SUCCESS) {
- destroy(true);
- setRequested(false);
- } else {
- if (mCanvas == null) {
- mCanvas = createCanvas();
- mCanvas.setName(mName);
- }
- setEnabled(true);
-
- if (contextCreated) {
- initAtlas();
- }
- }
-
- return mCanvas != null;
- }
- }
- return false;
- }
-
- @Override
- void updateSurface(Surface surface) throws OutOfResourcesException {
- if (isRequested() && isEnabled()) {
- createEglSurface(surface);
- }
- }
-
- abstract HardwareCanvas createCanvas();
-
- abstract int[] getConfig(boolean dirtyRegions);
-
- boolean initializeEgl() {
- synchronized (sEglLock) {
- if (sEgl == null && sEglConfig == null) {
- sEgl = (EGL10) EGLContext.getEGL();
-
- // Get to the default display.
- sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-
- if (sEglDisplay == EGL_NO_DISPLAY) {
- throw new RuntimeException("eglGetDisplay failed "
- + GLUtils.getEGLErrorString(sEgl.eglGetError()));
- }
-
- // We can now initialize EGL for that display
- int[] version = new int[2];
- if (!sEgl.eglInitialize(sEglDisplay, version)) {
- throw new RuntimeException("eglInitialize failed " +
- GLUtils.getEGLErrorString(sEgl.eglGetError()));
- }
-
- checkEglErrorsForced();
-
- sEglConfig = loadEglConfig();
- }
- }
-
- ManagedEGLContext managedContext = sEglContextStorage.get();
- mEglContext = managedContext != null ? managedContext.getContext() : null;
- mEglThread = Thread.currentThread();
-
- if (mEglContext == null) {
- mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
- sEglContextStorage.set(createManagedContext(mEglContext));
- return true;
- }
-
- return false;
- }
-
- private EGLConfig loadEglConfig() {
- EGLConfig eglConfig = chooseEglConfig();
- if (eglConfig == null) {
- // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
- if (sDirtyRegions) {
- sDirtyRegions = false;
- eglConfig = chooseEglConfig();
- if (eglConfig == null) {
- throw new RuntimeException("eglConfig not initialized");
- }
- } else {
- throw new RuntimeException("eglConfig not initialized");
- }
- }
- return eglConfig;
- }
-
- abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
-
- private EGLConfig chooseEglConfig() {
- EGLConfig[] configs = new EGLConfig[1];
- int[] configsCount = new int[1];
- int[] configSpec = getConfig(sDirtyRegions);
-
- // Debug
- final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
- if ("all".equalsIgnoreCase(debug)) {
- sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
-
- EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
- sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
- configsCount[0], configsCount);
-
- for (EGLConfig config : debugConfigs) {
- printConfig(config);
- }
- }
-
- if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
- throw new IllegalArgumentException("eglChooseConfig failed " +
- GLUtils.getEGLErrorString(sEgl.eglGetError()));
- } else if (configsCount[0] > 0) {
- if ("choice".equalsIgnoreCase(debug)) {
- printConfig(configs[0]);
- }
- return configs[0];
- }
-
- return null;
- }
-
- private static void printConfig(EGLConfig config) {
- int[] value = new int[1];
-
- Log.d(LOG_TAG, "EGL configuration " + config + ":");
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
- Log.d(LOG_TAG, " RED_SIZE = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
- Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
- Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
- Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
- Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
- Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
- Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
- Log.d(LOG_TAG, " SAMPLES = " + value[0]);
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
- Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
-
- sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
- Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
- }
-
- GL createEglSurface(Surface surface) throws OutOfResourcesException {
- // Check preconditions.
- if (sEgl == null) {
- throw new RuntimeException("egl not initialized");
- }
- if (sEglDisplay == null) {
- throw new RuntimeException("eglDisplay not initialized");
- }
- if (sEglConfig == null) {
- throw new RuntimeException("eglConfig not initialized");
- }
- if (Thread.currentThread() != mEglThread) {
- throw new IllegalStateException("HardwareRenderer cannot be used "
- + "from multiple threads");
- }
-
- // In case we need to destroy an existing surface
- destroySurface();
-
- // Create an EGL surface we can render into.
- if (!createSurface(surface)) {
- return null;
- }
-
- initCaches();
-
- return mEglContext.getGL();
- }
-
- private void enableDirtyRegions() {
- // If mDirtyRegions is set, this means we have an EGL configuration
- // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
- if (sDirtyRegions) {
- if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
- Log.w(LOG_TAG, "Backbuffer cannot be preserved");
- }
- } else if (sDirtyRegionsRequested) {
- // If mDirtyRegions is not set, our EGL configuration does not
- // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
- // swap behavior might be EGL_BUFFER_PRESERVED, which means we
- // want to set mDirtyRegions. We try to do this only if dirty
- // regions were initially requested as part of the device
- // configuration (see RENDER_DIRTY_REGIONS)
- mDirtyRegionsEnabled = isBackBufferPreserved();
- }
- }
-
- abstract void initCaches();
- abstract void initAtlas();
-
- EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
- int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
-
- EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
- mGlVersion != 0 ? attribs : null);
- if (context == null || context == EGL_NO_CONTEXT) {
- //noinspection ConstantConditions
- throw new IllegalStateException(
- "Could not create an EGL context. eglCreateContext failed with error: " +
- GLUtils.getEGLErrorString(sEgl.eglGetError()));
- }
-
- return context;
- }
-
- @Override
- void destroy(boolean full) {
- if (full && mCanvas != null) {
- mCanvas = null;
- }
-
- if (!isEnabled() || mDestroyed) {
- setEnabled(false);
- return;
- }
-
- destroySurface();
- setEnabled(false);
-
- mDestroyed = true;
- mGl = null;
- }
-
- void destroySurface() {
- if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
- if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
- sEgl.eglMakeCurrent(sEglDisplay,
- EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- }
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
- mEglSurface = null;
- }
- }
-
- @Override
- void invalidate(Surface surface) {
- // Cancels any existing buffer to ensure we'll get a buffer
- // of the right size before we call eglSwapBuffers
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
- if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
- mEglSurface = null;
- setEnabled(false);
- }
-
- if (surface.isValid()) {
- if (!createSurface(surface)) {
- return;
- }
-
- mUpdateDirtyRegions = true;
-
- if (mCanvas != null) {
- setEnabled(true);
- }
- }
- }
-
- private boolean createSurface(Surface surface) {
- mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
-
- if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
- int error = sEgl.eglGetError();
- if (error == EGL_BAD_NATIVE_WINDOW) {
- Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
- return false;
- }
- throw new RuntimeException("createWindowSurface failed "
- + GLUtils.getEGLErrorString(error));
- }
-
- if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- throw new IllegalStateException("eglMakeCurrent failed " +
- GLUtils.getEGLErrorString(sEgl.eglGetError()));
- }
-
- enableDirtyRegions();
-
- return true;
- }
-
- @Override
- boolean validate() {
- return checkRenderContext() != SURFACE_STATE_ERROR;
- }
-
- @Override
- void setup(int width, int height) {
- if (validate()) {
- mCanvas.setViewport(width, height);
- mWidth = width;
- mHeight = height;
- }
- }
-
- @Override
- int getWidth() {
- return mWidth;
- }
-
- @Override
- int getHeight() {
- return mHeight;
- }
-
- @Override
- HardwareCanvas getCanvas() {
- return mCanvas;
- }
-
- @Override
- void setName(String name) {
- mName = name;
- }
-
- boolean canDraw() {
- return mGl != null && mCanvas != null;
- }
-
- int onPreDraw(Rect dirty) {
- return DisplayList.STATUS_DONE;
- }
-
- void onPostDraw() {
- }
-
- class FunctorsRunnable implements Runnable {
- View.AttachInfo attachInfo;
-
- @Override
- public void run() {
- final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
- if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
- return;
- }
-
- if (checkRenderContext() != SURFACE_STATE_ERROR) {
- int status = mCanvas.invokeFunctors(mRedrawClip);
- handleFunctorStatus(attachInfo, status);
- }
- }
- }
-
- @Override
- void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
- Rect dirty) {
- if (canDraw()) {
- if (!hasDirtyRegions()) {
- dirty = null;
- }
- attachInfo.mIgnoreDirtyState = true;
- attachInfo.mDrawingTime = SystemClock.uptimeMillis();
-
- view.mPrivateFlags |= View.PFLAG_DRAWN;
-
- // We are already on the correct thread
- final int surfaceState = checkRenderContextUnsafe();
- if (surfaceState != SURFACE_STATE_ERROR) {
- HardwareCanvas canvas = mCanvas;
- attachInfo.mHardwareCanvas = canvas;
-
- if (mProfileEnabled) {
- mProfileLock.lock();
- }
-
- dirty = beginFrame(canvas, dirty, surfaceState);
-
- DisplayList displayList = buildDisplayList(view, canvas);
-
- // buildDisplayList() calls into user code which can cause
- // an eglMakeCurrent to happen with a different surface/context.
- // We must therefore check again here.
- if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
- return;
- }
-
- int saveCount = 0;
- int status = DisplayList.STATUS_DONE;
-
- long start = getSystemTime();
- try {
- status = prepareFrame(dirty);
-
- saveCount = canvas.save();
- callbacks.onHardwarePreDraw(canvas);
-
- if (displayList != null) {
- status |= drawDisplayList(attachInfo, canvas, displayList, status);
- } else {
- // Shouldn't reach here
- view.draw(canvas);
- }
- } catch (Exception e) {
- Log.e(LOG_TAG, "An error has occurred while drawing:", e);
- } finally {
- callbacks.onHardwarePostDraw(canvas);
- canvas.restoreToCount(saveCount);
- view.mRecreateDisplayList = false;
-
- mDrawDelta = getSystemTime() - start;
-
- if (mDrawDelta > 0) {
- mFrameCount++;
-
- debugOverdraw(attachInfo, dirty, canvas, displayList);
- debugDirtyRegions(dirty, canvas);
- drawProfileData(attachInfo);
- }
- }
-
- onPostDraw();
-
- swapBuffers(status);
-
- if (mProfileEnabled) {
- mProfileLock.unlock();
- }
-
- attachInfo.mIgnoreDirtyState = false;
- }
- }
- }
-
- abstract void countOverdraw(HardwareCanvas canvas);
- abstract float getOverdraw(HardwareCanvas canvas);
-
- private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
- HardwareCanvas canvas, DisplayList displayList) {
-
- if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
- if (mDebugOverdrawLayer == null) {
- mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
- } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
- mDebugOverdrawLayer.getHeight() != mHeight) {
- mDebugOverdrawLayer.resize(mWidth, mHeight);
- }
-
- if (!mDebugOverdrawLayer.isValid()) {
- mDebugOverdraw = -1;
- return;
- }
-
- HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
- countOverdraw(layerCanvas);
- final int restoreCount = layerCanvas.save();
- layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
- layerCanvas.restoreToCount(restoreCount);
- mDebugOverdrawLayer.end(canvas);
-
- float overdraw = getOverdraw(layerCanvas);
- DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
-
- drawOverdrawCounter(canvas, overdraw, metrics.density);
- }
- }
-
- private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
- final String text = String.format("%.2fx", overdraw);
- final Paint paint = setupPaint(density);
- // HSBtoColor will clamp the values in the 0..1 range
- paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
-
- canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
- }
-
- private Paint setupPaint(float density) {
- if (mDebugOverdrawPaint == null) {
- mDebugOverdrawPaint = new Paint();
- mDebugOverdrawPaint.setAntiAlias(true);
- mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
- mDebugOverdrawPaint.setTextSize(density * 20.0f);
- }
- return mDebugOverdrawPaint;
- }
-
- private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
- if (mDrawDelta <= 0) {
- return view.mDisplayList;
- }
-
- view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
- == View.PFLAG_INVALIDATED;
- view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
- long buildDisplayListStartTime = startBuildDisplayListProfiling();
- canvas.clearLayerUpdates();
-
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
- DisplayList displayList = view.getDisplayList();
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-
- endBuildDisplayListProfiling(buildDisplayListStartTime);
-
- return displayList;
- }
-
- abstract void drawProfileData(View.AttachInfo attachInfo);
-
- private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
- // We had to change the current surface and/or context, redraw everything
- if (surfaceState == SURFACE_STATE_UPDATED) {
- dirty = null;
- beginFrame(null);
- } else {
- int[] size = mSurfaceSize;
- beginFrame(size);
-
- if (size[1] != mHeight || size[0] != mWidth) {
- mWidth = size[0];
- mHeight = size[1];
-
- canvas.setViewport(mWidth, mHeight);
-
- dirty = null;
- }
- }
-
- if (mDebugDataProvider != null) dirty = null;
-
- return dirty;
- }
-
- private long startBuildDisplayListProfiling() {
- if (mProfileEnabled) {
- mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
- if (mProfileCurrentFrame >= mProfileData.length) {
- mProfileCurrentFrame = 0;
- }
-
- return System.nanoTime();
- }
- return 0;
- }
-
- private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
- if (mProfileEnabled) {
- long now = System.nanoTime();
- float total = (now - getDisplayListStartTime) * 0.000001f;
- //noinspection PointlessArithmeticExpression
- mProfileData[mProfileCurrentFrame] = total;
- }
- }
-
- private int prepareFrame(Rect dirty) {
- int status;
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
- try {
- status = onPreDraw(dirty);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- return status;
- }
-
- private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
- DisplayList displayList, int status) {
-
- long drawDisplayListStartTime = 0;
- if (mProfileEnabled) {
- drawDisplayListStartTime = System.nanoTime();
- }
-
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
- try {
- status |= canvas.drawDisplayList(displayList, mRedrawClip,
- DisplayList.FLAG_CLIP_CHILDREN);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
-
- if (mProfileEnabled) {
- long now = System.nanoTime();
- float total = (now - drawDisplayListStartTime) * 0.000001f;
- mProfileData[mProfileCurrentFrame + 1] = total;
- }
-
- handleFunctorStatus(attachInfo, status);
- return status;
- }
-
- private void swapBuffers(int status) {
- if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
- long eglSwapBuffersStartTime = 0;
- if (mProfileEnabled) {
- eglSwapBuffersStartTime = System.nanoTime();
- }
-
- sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
-
- if (mProfileEnabled) {
- long now = System.nanoTime();
- float total = (now - eglSwapBuffersStartTime) * 0.000001f;
- mProfileData[mProfileCurrentFrame + 2] = total;
- }
-
- checkEglErrors();
- }
- }
-
- private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
- if (mDebugDirtyRegions) {
- if (mDebugPaint == null) {
- mDebugPaint = new Paint();
- mDebugPaint.setColor(0x7fff0000);
- }
-
- if (dirty != null && (mFrameCount & 1) == 0) {
- canvas.drawRect(dirty, mDebugPaint);
- }
- }
- }
-
- private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
- // If the draw flag is set, functors will be invoked while executing
- // the tree of display lists
- if ((status & DisplayList.STATUS_DRAW) != 0) {
- if (mRedrawClip.isEmpty()) {
- attachInfo.mViewRootImpl.invalidate();
- } else {
- attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
- mRedrawClip.setEmpty();
- }
- }
-
- if ((status & DisplayList.STATUS_INVOKE) != 0 ||
- attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
- attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
- mFunctorsRunnable.attachInfo = attachInfo;
- attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
- }
- }
-
- @Override
- void detachFunctor(int functor) {
- if (mCanvas != null) {
- mCanvas.detachFunctor(functor);
- }
- }
-
- @Override
- boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
- if (mCanvas != null) {
- mCanvas.attachFunctor(functor);
- mFunctorsRunnable.attachInfo = attachInfo;
- attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
- attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
- return true;
- }
- return false;
- }
-
- /**
- * Ensures the current EGL context and surface are the ones we expect.
- * This method throws an IllegalStateException if invoked from a thread
- * that did not initialize EGL.
- *
- * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
- * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
- * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
- *
- * @see #checkRenderContextUnsafe()
- */
- int checkRenderContext() {
- if (mEglThread != Thread.currentThread()) {
- throw new IllegalStateException("Hardware acceleration can only be used with a " +
- "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
- "Current thread: " + Thread.currentThread());
- }
-
- return checkRenderContextUnsafe();
- }
-
- /**
- * Ensures the current EGL context and surface are the ones we expect.
- * This method does not check the current thread.
- *
- * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
- * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
- * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
- *
- * @see #checkRenderContext()
- */
- private int checkRenderContextUnsafe() {
- if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
- !mEglContext.equals(sEgl.eglGetCurrentContext())) {
- if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- Log.e(LOG_TAG, "eglMakeCurrent failed " +
- GLUtils.getEGLErrorString(sEgl.eglGetError()));
- fallback(true);
- return SURFACE_STATE_ERROR;
- } else {
- if (mUpdateDirtyRegions) {
- enableDirtyRegions();
- mUpdateDirtyRegions = false;
- }
- return SURFACE_STATE_UPDATED;
- }
- }
- return SURFACE_STATE_SUCCESS;
- }
-
- private static int dpToPx(int dp, float density) {
- return (int) (dp * density + 0.5f);
- }
-
- class DrawPerformanceDataProvider extends GraphDataProvider {
- private final int mGraphType;
-
- private int mVerticalUnit;
- private int mHorizontalUnit;
- private int mHorizontalMargin;
- private int mThresholdStroke;
-
- DrawPerformanceDataProvider(int graphType) {
- mGraphType = graphType;
- }
-
- @Override
- void prepare(DisplayMetrics metrics) {
- final float density = metrics.density;
-
- mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
- mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
- mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
- mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
- }
-
- @Override
- int getGraphType() {
- return mGraphType;
- }
-
- @Override
- int getVerticalUnitSize() {
- return mVerticalUnit;
- }
-
- @Override
- int getHorizontalUnitSize() {
- return mHorizontalUnit;
- }
-
- @Override
- int getHorizontaUnitMargin() {
- return mHorizontalMargin;
- }
-
- @Override
- float[] getData() {
- return mProfileData;
- }
-
- @Override
- float getThreshold() {
- return 16;
- }
-
- @Override
- int getFrameCount() {
- return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
- }
-
- @Override
- int getElementCount() {
- return PROFILE_FRAME_DATA_COUNT;
- }
-
- @Override
- int getCurrentFrame() {
- return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
- }
-
- @Override
- void setupGraphPaint(Paint paint, int elementIndex) {
- paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
- if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
- }
-
- @Override
- void setupThresholdPaint(Paint paint) {
- paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
- paint.setStrokeWidth(mThresholdStroke);
- }
-
- @Override
- void setupCurrentFramePaint(Paint paint) {
- paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
- if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
- }
- }
- }
-
- /**
- * Hardware renderer using OpenGL ES 2.0.
- */
- static class Gl20Renderer extends GlRenderer {
- private GLES20Canvas mGlCanvas;
-
- private DisplayMetrics mDisplayMetrics;
-
- private static EGLSurface sPbuffer;
- private static final Object[] sPbufferLock = new Object[0];
-
- static class Gl20RendererEglContext extends ManagedEGLContext {
- final Handler mHandler = new Handler();
-
- public Gl20RendererEglContext(EGLContext context) {
- super(context);
- }
-
- @Override
- public void onTerminate(final EGLContext eglContext) {
- // Make sure we do this on the correct thread.
- if (mHandler.getLooper() != Looper.myLooper()) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- onTerminate(eglContext);
- }
- });
- return;
- }
-
- synchronized (sEglLock) {
- if (sEgl == null) return;
-
- if (EGLImpl.getInitCount(sEglDisplay) == 1) {
- usePbufferSurface(eglContext);
- GLES20Canvas.terminateCaches();
-
- sEgl.eglDestroyContext(sEglDisplay, eglContext);
- sEglContextStorage.set(null);
- sEglContextStorage.remove();
-
- sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
- EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
- sEgl.eglReleaseThread();
- sEgl.eglTerminate(sEglDisplay);
-
- sEgl = null;
- sEglDisplay = null;
- sEglConfig = null;
- sPbuffer = null;
- }
- }
- }
- }
-
- Gl20Renderer(boolean translucent) {
- super(2, translucent);
- }
-
- @Override
- HardwareCanvas createCanvas() {
- return mGlCanvas = new GLES20Canvas(mTranslucent);
- }
-
- @Override
- ManagedEGLContext createManagedContext(EGLContext eglContext) {
- return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
- }
-
- @Override
- int[] getConfig(boolean dirtyRegions) {
- //noinspection PointlessBooleanExpression,ConstantConditions
- final int stencilSize = GLES20Canvas.getStencilSize();
- final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
-
- return new int[] {
- EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_DEPTH_SIZE, 0,
- EGL_CONFIG_CAVEAT, EGL_NONE,
- EGL_STENCIL_SIZE, stencilSize,
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE
- };
- }
-
- @Override
- void initCaches() {
- if (GLES20Canvas.initCaches()) {
- // Caches were (re)initialized, rebind atlas
- initAtlas();
- }
- }
-
- @Override
- void initAtlas() {
- IBinder binder = ServiceManager.getService("assetatlas");
- if (binder == null) return;
-
- IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
- try {
- if (atlas.isCompatible(android.os.Process.myPpid())) {
- GraphicBuffer buffer = atlas.getBuffer();
- if (buffer != null) {
- int[] map = atlas.getMap();
- if (map != null) {
- GLES20Canvas.initAtlas(buffer, map);
- }
- // If IAssetAtlas is not the same class as the IBinder
- // we are using a remote service and we can safely
- // destroy the graphic buffer
- if (atlas.getClass() != binder.getClass()) {
- buffer.destroy();
- }
- }
- }
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Could not acquire atlas", e);
- }
- }
-
- @Override
- boolean canDraw() {
- return super.canDraw() && mGlCanvas != null;
- }
-
- @Override
- int onPreDraw(Rect dirty) {
- return mGlCanvas.onPreDraw(dirty);
- }
-
- @Override
- void onPostDraw() {
- mGlCanvas.onPostDraw();
- }
-
- @Override
- void drawProfileData(View.AttachInfo attachInfo) {
- if (mDebugDataProvider != null) {
- final GraphDataProvider provider = mDebugDataProvider;
- initProfileDrawData(attachInfo, provider);
-
- final int height = provider.getVerticalUnitSize();
- final int margin = provider.getHorizontaUnitMargin();
- final int width = provider.getHorizontalUnitSize();
-
- int x = 0;
- int count = 0;
- int current = 0;
-
- final float[] data = provider.getData();
- final int elementCount = provider.getElementCount();
- final int graphType = provider.getGraphType();
-
- int totalCount = provider.getFrameCount() * elementCount;
- if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
- totalCount -= elementCount;
- }
-
- for (int i = 0; i < totalCount; i += elementCount) {
- if (data[i] < 0.0f) break;
-
- int index = count * 4;
- if (i == provider.getCurrentFrame() * elementCount) current = index;
-
- x += margin;
- int x2 = x + width;
-
- int y2 = mHeight;
- int y1 = (int) (y2 - data[i] * height);
-
- switch (graphType) {
- case GraphDataProvider.GRAPH_TYPE_BARS: {
- for (int j = 0; j < elementCount; j++) {
- //noinspection MismatchedReadAndWriteOfArray
- final float[] r = mProfileShapes[j];
- r[index] = x;
- r[index + 1] = y1;
- r[index + 2] = x2;
- r[index + 3] = y2;
-
- y2 = y1;
- if (j < elementCount - 1) {
- y1 = (int) (y2 - data[i + j + 1] * height);
- }
- }
- } break;
- case GraphDataProvider.GRAPH_TYPE_LINES: {
- for (int j = 0; j < elementCount; j++) {
- //noinspection MismatchedReadAndWriteOfArray
- final float[] r = mProfileShapes[j];
- r[index] = (x + x2) * 0.5f;
- r[index + 1] = index == 0 ? y1 : r[index - 1];
- r[index + 2] = r[index] + width;
- r[index + 3] = y1;
-
- y2 = y1;
- if (j < elementCount - 1) {
- y1 = (int) (y2 - data[i + j + 1] * height);
- }
- }
- } break;
- }
-
-
- x += width;
- count++;
- }
-
- x += margin;
-
- drawGraph(graphType, count);
- drawCurrentFrame(graphType, current);
- drawThreshold(x, height);
- }
- }
-
- private void drawGraph(int graphType, int count) {
- for (int i = 0; i < mProfileShapes.length; i++) {
- mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
- switch (graphType) {
- case GraphDataProvider.GRAPH_TYPE_BARS:
- mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
- break;
- case GraphDataProvider.GRAPH_TYPE_LINES:
- mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
- break;
- }
- }
- }
-
- private void drawCurrentFrame(int graphType, int index) {
- if (index >= 0) {
- mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
- switch (graphType) {
- case GraphDataProvider.GRAPH_TYPE_BARS:
- mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
- mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
- mProfilePaint);
- break;
- case GraphDataProvider.GRAPH_TYPE_LINES:
- mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
- mProfileShapes[2][index], mHeight, mProfilePaint);
- break;
- }
- }
- }
-
- private void drawThreshold(int x, int height) {
- float threshold = mDebugDataProvider.getThreshold();
- if (threshold > 0.0f) {
- mDebugDataProvider.setupThresholdPaint(mProfilePaint);
- int y = (int) (mHeight - threshold * height);
- mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
- }
- }
-
- private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
- if (mProfileShapes == null) {
- final int elementCount = provider.getElementCount();
- final int frameCount = provider.getFrameCount();
-
- mProfileShapes = new float[elementCount][];
- for (int i = 0; i < elementCount; i++) {
- mProfileShapes[i] = new float[frameCount * 4];
- }
-
- mProfilePaint = new Paint();
- }
-
- mProfilePaint.reset();
- if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
- mProfilePaint.setAntiAlias(true);
- }
-
- if (mDisplayMetrics == null) {
- mDisplayMetrics = new DisplayMetrics();
- }
-
- attachInfo.mDisplay.getMetrics(mDisplayMetrics);
- provider.prepare(mDisplayMetrics);
- }
-
- @Override
- void destroy(boolean full) {
- try {
- super.destroy(full);
- } finally {
- if (full && mGlCanvas != null) {
- mGlCanvas = null;
- }
- }
- }
-
- @Override
- void pushLayerUpdate(HardwareLayer layer) {
- mGlCanvas.pushLayerUpdate(layer);
- }
-
- @Override
- void cancelLayerUpdate(HardwareLayer layer) {
- mGlCanvas.cancelLayerUpdate(layer);
- }
-
- @Override
- void flushLayerUpdates() {
- mGlCanvas.flushLayerUpdates();
- }
-
- @Override
- HardwareLayer createHardwareLayer(boolean isOpaque) {
- return new GLES20TextureLayer(isOpaque);
- }
-
- @Override
- public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
- return new GLES20RenderLayer(width, height, isOpaque);
- }
-
- @Override
- void countOverdraw(HardwareCanvas canvas) {
- ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
- }
-
- @Override
- float getOverdraw(HardwareCanvas canvas) {
- return ((GLES20Canvas) canvas).getOverdraw();
- }
-
- @Override
- public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
- return ((GLES20TextureLayer) layer).getSurfaceTexture();
- }
-
- @Override
- void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
- ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
- }
-
- @Override
- boolean safelyRun(Runnable action) {
- boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
-
- if (needsContext) {
- Gl20RendererEglContext managedContext =
- (Gl20RendererEglContext) sEglContextStorage.get();
- if (managedContext == null) return false;
- usePbufferSurface(managedContext.getContext());
- }
-
- try {
- action.run();
- } finally {
- if (needsContext) {
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
- EGL_NO_SURFACE, EGL_NO_CONTEXT);
- }
- }
-
- return true;
- }
-
- @Override
- void destroyLayers(final View view) {
- if (view != null) {
- safelyRun(new Runnable() {
- @Override
- public void run() {
- if (mCanvas != null) {
- mCanvas.clearLayerUpdates();
- }
- destroyHardwareLayer(view);
- GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
- }
- });
- }
- }
-
- private static void destroyHardwareLayer(View view) {
- view.destroyLayer(true);
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyHardwareLayer(group.getChildAt(i));
- }
- }
- }
-
- @Override
- void destroyHardwareResources(final View view) {
- if (view != null) {
- safelyRun(new Runnable() {
- @Override
- public void run() {
- if (mCanvas != null) {
- mCanvas.clearLayerUpdates();
- }
- destroyResources(view);
- GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
- }
- });
- }
- }
-
- private static void destroyResources(View view) {
- view.destroyHardwareResources();
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyResources(group.getChildAt(i));
- }
- }
- }
-
- static HardwareRenderer create(boolean translucent) {
- if (GLES20Canvas.isAvailable()) {
- return new Gl20Renderer(translucent);
- }
- return null;
- }
-
- static void startTrimMemory(int level) {
- if (sEgl == null || sEglConfig == null) return;
-
- Gl20RendererEglContext managedContext =
- (Gl20RendererEglContext) sEglContextStorage.get();
- // We do not have OpenGL objects
- if (managedContext == null) {
- return;
- } else {
- usePbufferSurface(managedContext.getContext());
- }
-
- if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
- GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
- } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
- GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
- }
- }
-
- static void endTrimMemory() {
- if (sEgl != null && sEglDisplay != null) {
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- }
- }
-
- private static void usePbufferSurface(EGLContext eglContext) {
- synchronized (sPbufferLock) {
- // Create a temporary 1x1 pbuffer so we have a context
- // to clear our OpenGL objects
- if (sPbuffer == null) {
- sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
- EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
- });
- }
- }
- sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
- }
- }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d8a7efc..f9e6b9f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13358,20 +13358,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * @return The {@link HardwareRenderer} associated with that view or null if
- * hardware rendering is not supported or this view is not attached
- * to a window.
- *
- * @hide
- */
- public HardwareRenderer getHardwareRenderer() {
- if (mAttachInfo != null) {
- return mAttachInfo.mHardwareRenderer;
- }
- return null;
- }
-
- /**
* Returns a DisplayList. If the incoming displayList is null, one will be created.
* Otherwise, the same display list will be returned (after having been rendered into
* along the way, depending on the invalidation state of the view).
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 909907c..a5f797e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -718,7 +718,7 @@ public final class ViewRootImpl implements ViewParent,
}
final boolean translucent = attrs.format != PixelFormat.OPAQUE;
- mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
+ mAttachInfo.mHardwareRenderer = HardwareRenderer.create(translucent);
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
mAttachInfo.mHardwareAccelerated =
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 4c9f8a3..2e0c28e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -51,8 +51,8 @@ LOCAL_SRC_FILES:= \
android_view_InputQueue.cpp \
android_view_KeyEvent.cpp \
android_view_KeyCharacterMap.cpp \
- android_view_HardwareRenderer.cpp \
android_view_GraphicBuffer.cpp \
+ android_view_GLRenderer.cpp \
android_view_GLES20DisplayList.cpp \
android_view_GLES20Canvas.cpp \
android_view_MotionEvent.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1cce263..d501dd8 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -122,7 +122,7 @@ extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_GraphicBuffer(JNIEnv* env);
extern int register_android_view_GLES20DisplayList(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
-extern int register_android_view_HardwareRenderer(JNIEnv* env);
+extern int register_android_view_GLRenderer(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
@@ -1118,7 +1118,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_GraphicBuffer),
REG_JNI(register_android_view_GLES20DisplayList),
REG_JNI(register_android_view_GLES20Canvas),
- REG_JNI(register_android_view_HardwareRenderer),
+ REG_JNI(register_android_view_GLRenderer),
REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_SurfaceControl),
REG_JNI(register_android_view_SurfaceSession),
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 479fbe2..7cf93d0 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "HardwareRenderer"
+#define LOG_TAG "GLRenderer"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
@@ -60,7 +60,7 @@ namespace android {
// Surface and display management
// ----------------------------------------------------------------------------
-static jboolean android_view_HardwareRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
+static jboolean android_view_GLRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
EGLDisplay display = eglGetCurrentDisplay();
EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
@@ -75,7 +75,7 @@ static jboolean android_view_HardwareRenderer_preserveBackBuffer(JNIEnv* env, jo
return error == EGL_SUCCESS;
}
-static jboolean android_view_HardwareRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
+static jboolean android_view_GLRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
EGLDisplay display = eglGetCurrentDisplay();
EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
EGLint value;
@@ -95,14 +95,14 @@ static jboolean android_view_HardwareRenderer_isBackBufferPreserved(JNIEnv* env,
// Tracing and debugging
// ----------------------------------------------------------------------------
-static bool android_view_HardwareRenderer_loadProperties(JNIEnv* env, jobject clazz) {
+static bool android_view_GLRenderer_loadProperties(JNIEnv* env, jobject clazz) {
if (uirenderer::Caches::hasInstance()) {
return uirenderer::Caches::getInstance().initProperties();
}
return false;
}
-static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz,
+static void android_view_GLRenderer_beginFrame(JNIEnv* env, jobject clazz,
jintArray size) {
EGLDisplay display = eglGetCurrentDisplay();
@@ -124,7 +124,7 @@ static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz,
eglBeginFrame(display, surface);
}
-static jlong android_view_HardwareRenderer_getSystemTime(JNIEnv* env, jobject clazz) {
+static jlong android_view_GLRenderer_getSystemTime(JNIEnv* env, jobject clazz) {
if (uirenderer::Extensions::getInstance().hasNvSystemTime()) {
return eglGetSystemTimeNV();
}
@@ -137,7 +137,7 @@ static jlong android_view_HardwareRenderer_getSystemTime(JNIEnv* env, jobject cl
// Shaders
// ----------------------------------------------------------------------------
-static void android_view_HardwareRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
+static void android_view_GLRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
jstring diskCachePath) {
const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
@@ -149,24 +149,24 @@ static void android_view_HardwareRenderer_setupShadersDiskCache(JNIEnv* env, job
// JNI Glue
// ----------------------------------------------------------------------------
-const char* const kClassPathName = "android/view/HardwareRenderer";
+const char* const kClassPathName = "android/view/GLRenderer";
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
- { "nIsBackBufferPreserved", "()Z", (void*) android_view_HardwareRenderer_isBackBufferPreserved },
- { "nPreserveBackBuffer", "()Z", (void*) android_view_HardwareRenderer_preserveBackBuffer },
- { "nLoadProperties", "()Z", (void*) android_view_HardwareRenderer_loadProperties },
+ { "isBackBufferPreserved", "()Z", (void*) android_view_GLRenderer_isBackBufferPreserved },
+ { "preserveBackBuffer", "()Z", (void*) android_view_GLRenderer_preserveBackBuffer },
+ { "loadProperties", "()Z", (void*) android_view_GLRenderer_loadProperties },
- { "nBeginFrame", "([I)V", (void*) android_view_HardwareRenderer_beginFrame },
+ { "beginFrame", "([I)V", (void*) android_view_GLRenderer_beginFrame },
- { "nGetSystemTime", "()J", (void*) android_view_HardwareRenderer_getSystemTime },
+ { "getSystemTime", "()J", (void*) android_view_GLRenderer_getSystemTime },
#endif
- { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
- (void*) android_view_HardwareRenderer_setupShadersDiskCache },
+ { "setupShadersDiskCache", "(Ljava/lang/String;)V",
+ (void*) android_view_GLRenderer_setupShadersDiskCache },
};
-int register_android_view_HardwareRenderer(JNIEnv* env) {
+int register_android_view_GLRenderer(JNIEnv* env) {
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}