Merge "Allows to render with an OpenGL context inside a TextureView."
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 },
|
||||
|
||||
50
core/jni/android_view_TextureView.cpp
Normal file
50
core/jni/android_view_TextureView.cpp
Normal 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));
|
||||
}
|
||||
|
||||
};
|
||||
@@ -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 },
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user