Merge "Allows to render with an OpenGL context inside a TextureView."

This commit is contained in:
Romain Guy
2011-05-02 18:33:26 -07:00
committed by Android (Google) Code Review
22 changed files with 512 additions and 56 deletions

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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.
@@ -209,6 +212,14 @@ public class TextureView extends View {
protected final void onDraw(Canvas canvas) {
}
@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) {
@@ -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);
}

View File

@@ -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 \

View File

@@ -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),

View File

@@ -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 },

View File

@@ -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));
}
};

View File

@@ -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 },

View File

@@ -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();

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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]);
}

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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"

View File

@@ -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;
}
}
}

View File

@@ -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
}
}