Fix missing first frame
Bug: 26776366
Change-Id: I46258c0ff35fdefe5c9f2ee610c904b2dbe8c5d9
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 6a3c890..44a24c8 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -47,6 +47,9 @@
return false;
}
+ int getWidth() { return mWidth; }
+ int getHeight() { return mHeight; }
+
ANDROID_API bool setBlend(bool blend) {
if (blend != mBlend) {
mBlend = blend;
@@ -75,6 +78,10 @@
mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
}
+ SkMatrix* getTransform() {
+ return mTransform;
+ }
+
ANDROID_API void setPaint(const SkPaint* paint);
void apply();
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index dc967e0..2fb76ce 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -669,6 +669,7 @@
}
void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
+ if (CC_UNLIKELY(!op.layer->isRenderable())) return;
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index e00ae66..1e5498b 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -216,6 +216,10 @@
this->renderTarget = renderTarget;
}
+ inline bool isRenderable() const {
+ return renderTarget != GL_NONE;
+ }
+
void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
texture.setWrap(wrap, bindTexture, force, renderTarget);
}
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 5bce8ac..137316f 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -353,7 +353,7 @@
bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
- if (layer && layer->getRenderTarget() != GL_NONE
+ if (layer && layer->isRenderable()
&& bitmap->width() <= caches.maxTextureSize
&& bitmap->height() <= caches.maxTextureSize) {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index cf78781..4eeadb7 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -574,15 +574,19 @@
// We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
mDisplayList->ref(layerHandle);
- Layer* layer = layerHandle->backingLayer();
+ // Note that the backing layer has *not* yet been updated, so don't trust
+ // its width, height, transform, etc...!
Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
- totalTransform.multiply(layer->getTransform());
+ if (layerHandle->getTransform()) {
+ Matrix4 layerTransform(*layerHandle->getTransform());
+ totalTransform.multiply(layerTransform);
+ }
addOp(alloc().create_trivial<TextureLayerOp>(
- Rect(layer->getWidth(), layer->getHeight()),
+ Rect(layerHandle->getWidth(), layerHandle->getHeight()),
totalTransform,
getRecordedClip(),
- layer));
+ layerHandle->backingLayer()));
}
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index de7b9c2..18fd985 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -347,6 +347,15 @@
</activity>
<activity
+ android:name="SingleFrameTextureViewTestActivity"
+ android:label="TextureView/SingleFrameTextureViewTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="HardwareCanvasSurfaceViewActivity"
android:label="SurfaceView/HardwareCanvas">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
new file mode 100644
index 0000000..4d3826b68
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 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 com.android.test.hwui;
+
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLUtils;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+public class SingleFrameTextureViewTestActivity extends Activity implements SurfaceTextureListener {
+ private static final String LOG_TAG = "SingleFrameTest";
+
+ private View mPreview;
+ private TextureView mTextureView;
+ private Thread mGLThread;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ TextView preview = new TextView(this);
+ preview.setText("This is a preview");
+ preview.setBackgroundColor(Color.WHITE);
+ mPreview = preview;
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ FrameLayout content = new FrameLayout(this);
+ content.addView(mTextureView,
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ content.addView(mPreview,
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ setContentView(content);
+ }
+
+ private void stopGlThread() {
+ if (mGLThread != null) {
+ try {
+ mGLThread.join();
+ mGLThread = null;
+ } catch (InterruptedException e) { }
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ Log.d(LOG_TAG, "onSurfaceAvailable");
+ mGLThread = new Thread() {
+ static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ static final int EGL_OPENGL_ES2_BIT = 4;
+
+ private EGL10 mEgl;
+ private EGLDisplay mEglDisplay;
+ private EGLConfig mEglConfig;
+ private EGLContext mEglContext;
+ private EGLSurface mEglSurface;
+
+ @Override
+ public void run() {
+ initGL();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {}
+
+ for (int i = 0; i < 2; i++) {
+ if (i == 0) {
+ glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+ } else {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ Log.d(LOG_TAG, "eglSwapBuffers");
+ if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+ throw new RuntimeException("Cannot swap buffers");
+ }
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {}
+ }
+
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {}
+
+ finishGL();
+ }
+
+ private void finishGL() {
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ }
+
+ private void initGL() {
+ mEgl = (EGL10) EGLContext.getEGL();
+
+ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed "
+ + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ int[] version = new int[2];
+ if (!mEgl.eglInitialize(mEglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed " +
+ GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ mEglConfig = chooseEglConfig();
+ if (mEglConfig == null) {
+ throw new RuntimeException("eglConfig not initialized");
+ }
+
+ mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+ mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
+
+ if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+ int error = mEgl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+ Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ return;
+ }
+ throw new RuntimeException("createWindowSurface failed "
+ + GLUtils.getEGLErrorString(error));
+ }
+
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed "
+ + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ }
+ }
+
+
+ EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ }
+
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig();
+ if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ private int[] getConfig() {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL10.EGL_NONE
+ };
+ }
+ };
+ mGLThread.start();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ Log.d(LOG_TAG, "onSurfaceTextureSizeChanged");
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ Log.d(LOG_TAG, "onSurfaceTextureDestroyed");
+ stopGlThread();
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ Log.d(LOG_TAG, "onSurfaceTextureUpdated");
+ mPreview.setVisibility(View.GONE);
+ }
+}