diff options
| -rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 7 | ||||
| -rw-r--r-- | libs/hwui/FrameBuilder.cpp | 1 | ||||
| -rw-r--r-- | libs/hwui/Layer.h | 4 | ||||
| -rw-r--r-- | libs/hwui/LayerRenderer.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 12 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 9 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java | 217 |
7 files changed, 247 insertions, 5 deletions
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 6a3c8902dff1..44a24c840892 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -47,6 +47,9 @@ public: 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 @@ public: 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 dc967e046f11..2fb76ce13048 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -669,6 +669,7 @@ void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) { } 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 e00ae66997a5..1e5498bb3d21 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -216,6 +216,10 @@ public: 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 5bce8ac83020..137316f57725 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -353,7 +353,7 @@ void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) { 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 cf78781e8f81..4eeadb7ad30f 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -574,15 +574,19 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { // 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 de7b9c268c99..18fd98528855 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 000000000000..4d3826b68247 --- /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); + } +} |