diff options
22 files changed, 512 insertions, 56 deletions
diff --git a/api/current.txt b/api/current.txt index a98ffae..a7f0368 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21025,6 +21025,7 @@ package android.view { public static abstract interface TextureView.SurfaceTextureListener { method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture); + method public abstract void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int); } public class TouchDelegate { diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index cdf8954..984102a 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -163,8 +163,7 @@ class GLES20Canvas extends HardwareCanvas { static native int nCreateTextureLayer(int[] layerInfo); static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo); static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo); - static native void nUpdateTextureLayer(int layerId, int width, int height, - float[] textureTransform); + static native void nUpdateTextureLayer(int layerId, int width, int height, int surface); static native void nDestroyLayer(int layerId); static native void nDestroyLayerDeferred(int layerId); diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java index 21fbdfc..fcf421b 100644 --- a/core/java/android/view/GLES20TextureLayer.java +++ b/core/java/android/view/GLES20TextureLayer.java @@ -70,7 +70,7 @@ class GLES20TextureLayer extends GLES20Layer { return mSurface; } - void update(int width, int height, float[] textureTransform) { - GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, textureTransform); + void update(int width, int height, int surface) { + GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, surface); } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 9a9b7b7..7ca6e09 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -202,11 +202,10 @@ public abstract class HardwareRenderer { * @param layer The hardware layer to update * @param width The layer's width * @param height The layer's height - * @param textureTransform A 4x4 column-first transform matrix to apply to - * texture coordinates + * @param surface The surface to update */ abstract void updateTextureLayer(HardwareLayer layer, int width, int height, - float[] textureTransform); + SurfaceTexture surface); /** * Initializes the hardware renderer for the specified surface and setup the @@ -800,8 +799,8 @@ public abstract class HardwareRenderer { @Override void updateTextureLayer(HardwareLayer layer, int width, int height, - float[] textureTransform) { - ((GLES20TextureLayer) layer).update(width, height, textureTransform); + SurfaceTexture surface) { + ((GLES20TextureLayer) layer).update(width, height, surface.mSurfaceTexture); } static HardwareRenderer create(boolean translucent) { diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 6380e1b..755ecf5 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -73,6 +73,10 @@ import android.util.Log; * // Something bad happened * } * } + * + * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + * // Ignored, Camera does all the work for us + * } * } * </pre> * @@ -90,8 +94,6 @@ public class TextureView extends View { private HardwareLayer mLayer; private SurfaceTexture mSurface; private SurfaceTextureListener mListener; - - private final float[] mTextureTransform = new float[16]; private final Runnable mUpdateLayerAction = new Runnable() { @Override @@ -99,6 +101,7 @@ public class TextureView extends View { updateLayer(); } }; + private SurfaceTexture.OnFrameAvailableListener mUpdateListener; /** * Creates a new TextureView. @@ -210,6 +213,14 @@ public class TextureView extends View { } @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (mSurface != null) { + nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight()); + } + } + + @Override HardwareLayer getHardwareLayer() { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { return null; @@ -218,15 +229,17 @@ public class TextureView extends View { if (mLayer == null) { mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(); mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer); + nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight()); - mSurface.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { + mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { // Per SurfaceTexture's documentation, the callback may be invoked // from an arbitrary thread post(mUpdateLayerAction); } - }); + }; + mSurface.setOnFrameAvailableListener(mUpdateListener); if (mListener != null) { mListener.onSurfaceTextureAvailable(mSurface); @@ -236,16 +249,29 @@ public class TextureView extends View { return mLayer; } + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + + if (mSurface != null) { + // When the view becomes invisible, stop updating it, it's a waste of CPU + // To cancel updates, the easiest thing to do is simply to remove the + // updates listener + if (visibility == VISIBLE) { + mSurface.setOnFrameAvailableListener(mUpdateListener); + updateLayer(); + } else { + mSurface.setOnFrameAvailableListener(null); + } + } + } + private void updateLayer() { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { return; } - mSurface.updateTexImage(); - mSurface.getTransformMatrix(mTextureTransform); - - mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), - mTextureTransform); + mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), mSurface); invalidate(); } @@ -292,5 +318,17 @@ public class TextureView extends View { * {@link android.view.TextureView#getSurfaceTexture()} */ public void onSurfaceTextureAvailable(SurfaceTexture surface); + + /** + * Invoked when the {@link SurfaceTexture}'s buffers size changed. + * + * @param surface The surface returned by + * {@link android.view.TextureView#getSurfaceTexture()} + * @param width The new width of the surface + * @param height The new height of the surface + */ + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height); } + + private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height); } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 290f528..95224a4 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -47,6 +47,7 @@ LOCAL_SRC_FILES:= \ android_emoji_EmojiFactory.cpp \ android_view_Display.cpp \ android_view_Surface.cpp \ + android_view_TextureView.cpp \ android_view_ViewRoot.cpp \ android_view_InputChannel.cpp \ android_view_InputQueue.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index a4a229a..c915753 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -118,6 +118,7 @@ extern int register_com_android_internal_graphics_NativeUtils(JNIEnv *env); extern int register_android_view_Display(JNIEnv* env); extern int register_android_view_GLES20Canvas(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env); +extern int register_android_view_TextureView(JNIEnv* env); extern int register_android_view_ViewRoot(JNIEnv* env); extern int register_android_database_CursorWindow(JNIEnv* env); extern int register_android_database_SQLiteCompiledSql(JNIEnv* env); @@ -1122,6 +1123,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Graphics), REG_JNI(register_android_view_GLES20Canvas), REG_JNI(register_android_view_Surface), + REG_JNI(register_android_view_TextureView), REG_JNI(register_android_view_ViewRoot), REG_JNI(register_com_google_android_gles_jni_EGLImpl), REG_JNI(register_com_google_android_gles_jni_GLImpl), diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index af7639a..f929a0e 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -24,6 +24,8 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/ResourceTypes.h> +#include <gui/SurfaceTexture.h> + #include <SkBitmap.h> #include <SkCanvas.h> #include <SkMatrix.h> @@ -577,10 +579,13 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz, } static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz, - Layer* layer, jint width, jint height, jfloatArray texTransform) { - jfloat* transform = env->GetFloatArrayElements(texTransform, NULL); - LayerRenderer::updateTextureLayer(layer, width, height, transform); - env->ReleaseFloatArrayElements(texTransform, transform, 0); + Layer* layer, jint width, jint height, SurfaceTexture* surface) { + float transform[16]; + surface->updateTexImage(); + surface->getTransformMatrix(transform); + GLenum renderTarget = surface->getCurrentTextureTarget(); + + LayerRenderer::updateTextureLayer(layer, width, height, renderTarget, transform); } static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) { @@ -717,7 +722,7 @@ static JNINativeMethod gMethods[] = { { "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer }, { "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer }, { "nCreateTextureLayer", "([I)I", (void*) android_view_GLES20Canvas_createTextureLayer }, - { "nUpdateTextureLayer", "(III[F)V" , (void*) android_view_GLES20Canvas_updateTextureLayer }, + { "nUpdateTextureLayer", "(IIII)V", (void*) android_view_GLES20Canvas_updateTextureLayer }, { "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer }, { "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred }, { "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer }, diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp new file mode 100644 index 0000000..c5d86c8 --- /dev/null +++ b/core/jni/android_view_TextureView.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 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. + */ + +#include "jni.h" +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> + +#include <gui/SurfaceTexture.h> + +namespace android { + +// ---------------------------------------------------------------------------- +// Native layer +// ---------------------------------------------------------------------------- + +static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject, + jint surfaceTexture, jint width, jint height) { + + sp<SurfaceTexture> surface = reinterpret_cast<SurfaceTexture*>(surfaceTexture); + surface->setDefaultBufferSize(width, height); +} + +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/view/TextureView"; + +static JNINativeMethod gMethods[] = { + { "nSetDefaultBufferSize", "(III)V", (void*) android_view_TextureView_setDefaultBufferSize } +}; + +int register_android_view_TextureView(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); +} + +}; diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index 5f2065a..f777527 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -27,6 +27,9 @@ #include <SkBitmap.h> #include <SkPixelRef.h> +#include <gui/SurfaceTexture.h> +#include <gui/SurfaceTextureClient.h> + namespace android { static jclass gConfig_class; @@ -319,6 +322,35 @@ not_valid_surface: return (jint)sur; } +static jint jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display, + jobject config, jint native_window, jintArray attrib_list) { + if (display == NULL || config == NULL + || !validAttribList(_env, attrib_list)) { + jniThrowException(_env, "java/lang/IllegalArgumentException", NULL); + return JNI_FALSE; + } + EGLDisplay dpy = getDisplay(_env, display); + EGLContext cnf = getConfig(_env, config); + sp<ANativeWindow> window; + if (native_window == 0) { +not_valid_surface: + jniThrowException(_env, "java/lang/IllegalArgumentException", + "Make sure the SurfaceTexture is valid"); + return 0; + } + + sp<SurfaceTexture> surfaceTexture = reinterpret_cast<SurfaceTexture*>(native_window); + + window = new SurfaceTextureClient(surfaceTexture); + if (window == NULL) + goto not_valid_surface; + + jint* base = beginNativeAttribList(_env, attrib_list); + EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base); + endNativeAttributeList(_env, attrib_list, base); + return (jint)sur; +} + static jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display, jobject config, jint attribute, jintArray value) { if (display == NULL || config == NULL @@ -508,6 +540,7 @@ static JNINativeMethod methods[] = { {"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface }, {"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface }, {"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface }, +{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG "I[I)I", (void*)jni_eglCreateWindowSurfaceTexture }, {"eglDestroyContext", "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext }, {"eglDestroySurface", "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface }, {"eglMakeCurrent", "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent }, diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index cfae0c1..3c43a39 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -34,8 +34,9 @@ import android.os.Message; * the stream to be skipped. * * <p>When sampling from the texture one should first transform the texture coordinates using the - * matrix queried via {@link #getTransformMatrix}. The transform matrix may change each time {@link - * #updateTexImage} is called, so it should be re-queried each time the texture image is updated. + * matrix queried via {@link #getTransformMatrix(float[])}. The transform matrix may change each + * time {@link #updateTexImage} is called, so it should be re-queried each time the texture image + * is updated. * This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s, * t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in * the streamed texture. This transform compensates for any properties of the image stream source @@ -63,8 +64,13 @@ public class SurfaceTexture { private EventHandler mEventHandler; private OnFrameAvailableListener mOnFrameAvailableListener; - @SuppressWarnings("unused") - private int mSurfaceTexture; + /** + * This field is used by native code, do not access or modify. + * + * @hide + */ + @SuppressWarnings({"UnusedDeclaration"}) + public int mSurfaceTexture; /** * Callback interface for being notified that a new stream frame is available. @@ -176,10 +182,13 @@ public class SurfaceTexture { if (mOnFrameAvailableListener != null) { mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this); } - return; } } + /** + * This method is invoked from native code only. + */ + @SuppressWarnings({"UnusedDeclaration"}) private static void postEventFromNative(Object selfRef) { WeakReference weakSelf = (WeakReference)selfRef; SurfaceTexture st = (SurfaceTexture)weakSelf.get(); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 16566b8..0310bc3 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -47,6 +47,7 @@ struct Layer { meshElementCount = 0; isCacheable = true; isTextureLayer = false; + renderTarget = GL_TEXTURE_2D; } ~Layer() { @@ -155,6 +156,11 @@ struct Layer { * Optional texture coordinates transform. */ mat4 texTransform; + + /** + * Indicates the render target. + */ + GLenum renderTarget; }; // struct Layer }; // namespace uirenderer diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index e167336..f316ba7 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -185,17 +185,7 @@ Layer* LayerRenderer::createTextureLayer() { layer->region.clear(); glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &layer->texture); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, layer->texture); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return layer; } @@ -280,7 +270,7 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { } void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - float* transform) { + GLenum renderTarget, float* transform) { if (layer) { layer->width = width; layer->height = height; @@ -288,6 +278,15 @@ void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t he layer->region.set(width, height); layer->regionRect.set(0.0f, 0.0f, width, height); layer->texTransform.load(transform); + layer->renderTarget = renderTarget; + + glBindTexture(layer->renderTarget, layer->texture); + + glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } } diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index b3cd5db..59cab96 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -57,7 +57,7 @@ public: static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - float* transform); + GLenum renderTarget, float* transform); static void destroyLayer(Layer* layer); static void destroyLayerDeferred(Layer* layer); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 049e9b7..6f751e8 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -637,7 +637,12 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { float alpha = layer->alpha / 255.0f; setupDraw(); - setupDrawWithExternalTexture(); + if (layer->renderTarget == GL_TEXTURE_2D) { + setupDrawWithTexture(); + } else { + setupDrawWithExternalTexture(); + } + setupDrawTextureTransform(); setupDrawColor(alpha, alpha, alpha, alpha); setupDrawColorFilter(); setupDrawBlending(layer->blend, layer->mode); @@ -645,8 +650,12 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); - setupDrawExternalTexture(layer->texture); - setupDrawTextureTransform(layer->texTransform); + if (layer->renderTarget == GL_TEXTURE_2D) { + setupDrawTexture(layer->texture); + } else { + setupDrawExternalTexture(layer->texture); + } + setupDrawTextureTransformUniforms(layer->texTransform); setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); @@ -1095,7 +1104,11 @@ void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { glEnableVertexAttribArray(mTexCoordsSlot); } -void OpenGLRenderer::setupDrawTextureTransform(mat4& transform) { +void OpenGLRenderer::setupDrawTextureTransform() { + mDescription.hasTextureTransform = true; +} + +void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) { glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1, GL_FALSE, &transform.data[0]); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 6ffd931..b5c37c2 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -465,7 +465,8 @@ private: void setupDrawSimpleMesh(); void setupDrawTexture(GLuint texture); void setupDrawExternalTexture(GLuint texture); - void setupDrawTextureTransform(mat4& transform); + void setupDrawTextureTransform(); + void setupDrawTextureTransformUniforms(mat4& transform); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void setupDrawVertices(GLvoid* vertices); void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords, diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 5bfe7a3..d419e3e 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -394,7 +394,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description } // Uniforms shader.append(gVS_Header_Uniforms); - if (description.hasExternalTexture) { + if (description.hasTextureTransform) { shader.append(gVS_Header_Uniforms_TextureTransform); } if (description.hasGradient) { @@ -424,11 +424,10 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description // Begin the shader shader.append(gVS_Main); { - if (description.hasTexture) { - shader.append(gVS_Main_OutTexCoords); - } - if (description.hasExternalTexture) { + if (description.hasTextureTransform) { shader.append(gVS_Main_OutTransformedTexCoords); + } else if (description.hasTexture || description.hasExternalTexture) { + shader.append(gVS_Main_OutTexCoords); } if (description.isAA) { shader.append(gVS_Main_AA); @@ -496,8 +495,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); - } - if (description.hasExternalTexture) { + } else if (description.hasExternalTexture) { shader.append(gFS_Uniforms_ExternalTextureSampler); } if (description.isAA) { diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index 2586636..5c7197b 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -78,6 +78,7 @@ namespace uirenderer { #define PROGRAM_HAS_AA_SHIFT 37 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 +#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 /////////////////////////////////////////////////////////////////////////////// // Types @@ -116,6 +117,7 @@ struct ProgramDescription { bool hasTexture; bool hasAlpha8Texture; bool hasExternalTexture; + bool hasTextureTransform; // Modulate, this should only be set when setColor() return true bool modulate; @@ -155,6 +157,7 @@ struct ProgramDescription { hasTexture = false; hasAlpha8Texture = false; hasExternalTexture = false; + hasTextureTransform = false; isAA = false; @@ -245,6 +248,7 @@ struct ProgramDescription { if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; + if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; return key; } diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java index 8a7124d..f162d40 100644 --- a/opengl/java/com/google/android/gles_jni/EGLImpl.java +++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java @@ -18,10 +18,10 @@ package com.google.android.gles_jni; import javax.microedition.khronos.egl.*; +import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceView; import android.view.SurfaceHolder; -import android.view.View; public class EGLImpl implements EGL10 { private EGLContextImpl mContext = new EGLContextImpl(-1); @@ -71,19 +71,28 @@ public class EGLImpl implements EGL10 { } public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) { - Surface sur; + Surface sur = null; if (native_window instanceof SurfaceView) { SurfaceView surfaceView = (SurfaceView)native_window; sur = surfaceView.getHolder().getSurface(); } else if (native_window instanceof SurfaceHolder) { SurfaceHolder holder = (SurfaceHolder)native_window; sur = holder.getSurface(); + } + + int eglSurfaceId; + if (sur != null) { + eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list); + } else if (native_window instanceof SurfaceTexture) { + eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config, + ((SurfaceTexture) native_window).mSurfaceTexture, attrib_list); } else { throw new java.lang.UnsupportedOperationException( "eglCreateWindowSurface() can only be called with an instance of " + - "SurfaceView or SurfaceHolder at the moment, this will be fixed later."); + "SurfaceView, SurfaceHolder or SurfaceTexture at the moment, " + + "this will be fixed later."); } - int eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list); + if (eglSurfaceId == 0) { return EGL10.EGL_NO_SURFACE; } @@ -134,6 +143,7 @@ public class EGLImpl implements EGL10 { private native int _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list); private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list); private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list); + private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, int native_window, int[] attrib_list); private native int _eglGetDisplay(Object native_display); private native int _eglGetCurrentContext(); private native int _eglGetCurrentDisplay(); diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index c5c3f70..6285880 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -37,6 +37,15 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <activity + android:name="GLTextureViewActivity" + android:label="_TextureViewGL"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> <activity android:name="BitmapMeshActivity" diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java new file mode 100644 index 0000000..7f97098 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2011 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 android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.graphics.SurfaceTexture; +import android.opengl.GLES20; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.TextureView; +import android.view.View; +import android.widget.FrameLayout; + +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; + +@SuppressWarnings({"UnusedDeclaration"}) +public class GLTextureViewActivity extends Activity implements TextureView.SurfaceTextureListener { + private RenderThread mRenderThread; + private TextureView mTextureView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mTextureView = new TextureView(this); + mTextureView.setSurfaceTextureListener(this); + + setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER)); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mRenderThread.finish(); + } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface) { + mRenderThread = new RenderThread(surface); + mRenderThread.start(); + + mTextureView.setCameraDistance(5000); + + ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f); + animator.setRepeatMode(ObjectAnimator.REVERSE); + animator.setRepeatCount(ObjectAnimator.INFINITE); + animator.setDuration(4000); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + ((View) mTextureView.getParent()).invalidate(); + } + }); + animator.start(); + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + } + + private static class RenderThread extends Thread { + private static final String LOG_TAG = "GLTextureView"; + + static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + static final int EGL_SURFACE_TYPE = 0x3033; + static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; + static final int EGL_OPENGL_ES2_BIT = 4; + + private volatile boolean mFinished; + + private SurfaceTexture mSurface; + + private EGL10 mEgl; + private EGLDisplay mEglDisplay; + private EGLConfig mEglConfig; + private EGLContext mEglContext; + private EGLSurface mEglSurface; + private GL mGL; + + RenderThread(SurfaceTexture surface) { + mSurface = surface; + } + + @Override + public void run() { + initGL(); + + float red = 0.0f; + while (!mFinished) { + checkCurrent(); + + GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f); + int error = GLES20.glGetError(); + if (error != GLES20.GL_NO_ERROR) { + Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); + } + + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + error = GLES20.glGetError(); + if (error != GLES20.GL_NO_ERROR) { + Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); + } + + if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { + throw new RuntimeException("Cannot swap buffers"); + } + + try { + Thread.sleep(20); + } catch (InterruptedException e) { + // Ignore + } + + red += 0.021f; + if (red > 1.0f) red = 0.0f; + } + + finishGL(); + } + + private void finishGL() { + mEgl.eglDestroyContext(mEglDisplay, mEglContext); + mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + } + + private void checkCurrent() { + if (!mEglContext.equals(mEgl.eglGetCurrentContext()) || + !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { + if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + throw new RuntimeException("eglMakeCurrent failed " + + getEGLErrorString(mEgl.eglGetError())); + } + } + } + + 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 " + + getEGLErrorString(mEgl.eglGetError())); + } + + int[] version = new int[2]; + if (!mEgl.eglInitialize(mEglDisplay, version)) { + throw new RuntimeException("eglInitialize failed " + + getEGLErrorString(mEgl.eglGetError())); + } + + mEglConfig = chooseEglConfig(); + if (mEglConfig == null) { + throw new RuntimeException("eglConfig not initialized"); + } + + mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); + + mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, 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 " + + getEGLErrorString(error)); + } + + if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + throw new RuntimeException("eglMakeCurrent failed " + + getEGLErrorString(mEgl.eglGetError())); + } + + mGL = mEglContext.getGL(); + } + + + 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 " + + 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 + }; + } + + static String getEGLErrorString(int error) { + switch (error) { + case EGL10.EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL10.EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED"; + case EGL10.EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL10.EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL10.EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL10.EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL10.EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL10.EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL10.EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL10.EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL10.EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL10.EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + case EGL10.EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL10.EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + case EGL11.EGL_CONTEXT_LOST: + return "EGL_CONTEXT_LOST"; + default: + return "0x" + Integer.toHexString(error); + } + } + + void finish() { + mFinished = true; + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java index 4726672..2feda57 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java @@ -84,4 +84,9 @@ public class TextureViewActivity extends Activity implements TextureView.Surface animator.setDuration(4000); animator.start(); } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + // Ignored, the Camera does all the work for us + } } |