Android 原生的View渲染到OpenGL GLSurfaceView中,
Posted zhangtian6691844
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 原生的View渲染到OpenGL GLSurfaceView中,相关的知识,希望对你有一定的参考价值。
要把android 原生的View渲染到OpenGL GLSurfaceView中,起初想到的是截图的方法,也就是把View截取成bitmap后,再把Bitmap渲染到OpenGL中;但是明显这种方法是不可行的,面对一些高速动态更新的View,只有不停的对view 进行截图才能渲染出原生View的效果。不过经过测试该方法只能渲染直接父类为View的view,也就是只能渲染一层View(如progressbar,没不能添加child的view),当该原生Android View包含很多子view时(也就是根View为FramLayout、或者linearLayout之类),无法实时的监听到View动态改变,OpenGL中只能不停的渲染该view,才能渲染出原生View的效果。但是这样一来不同的渲染会耗费大量的资源,降低应用程序的效率。理想中的话,是监听到了该View的内容或者其子view 的内容发生了变化(如:View中的字幕发生滚动)才进行渲染。
步骤一:重写根View
1.设置该View 绘制自己:
setWillNotDraw(false);
2.监听View的变化,重写View,用ViewTreeObServer来监听,方法如下:
private void addOnPreDrawListener()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
final ViewTreeObserver mObserver = getViewTreeObserver();
if (mObserver != null)
mObserver.addOnPreDrawListener(new OnPreDrawListener()
@Override
public boolean onPreDraw()
if (isDirty()) //View或者子view发生变化
invalidate();
return true;
);
3.重写该View的onDraw方法:
@Override
protected void onDraw(Canvas canvas)
try
if (mSurface != null)
Canvas surfaceCanvas = mSurface.lockCanvas(null);
super.dispatchDraw(surfaceCanvas);
mSurface.unlockCanvasAndPost(surfaceCanvas);
mSurface.release();
mSurface = null;
mSurface = new Surface(mSurfaceTexture);
catch (OutOfResourcesException e)
e.printStackTrace();
步骤二:GLSurfaceView.Renderer
class CustomRenderer implements GLSurfaceView.Renderer
int glSurfaceTex;
private final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
long currentTime;
long previousTime;
boolean b = false;
int frameCount = 0;
DirectDrawer mDirectDrawer;
ActivityManager activityManager;
MemoryInfo _memoryInfo;
// Fixed values
private int TEXTURE_WIDTH = 360;
private int TEXTURE_HEIGHT = 360;
Context context;
private LauncherAppWidgetHostView addedWidgetView;
private SurfaceTexture surfaceTexture = null;
private Surface surface;
float fps;
public CustomRenderer(Context context, LauncherAppWidgetHostView addedWidgetView, Display mDisplay)
this.context = context;
this.addedWidgetView = addedWidgetView;
TEXTURE_WIDTH = mDisplay.getWidth();
TEXTURE_HEIGHT = mDisplay.getHeight();
_memoryInfo = new MemoryInfo();
activityManager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
@Override
public void onDrawFrame(GL10 gl)
synchronized (this)
surfaceTexture.updateTexImage();
activityManager.getMemoryInfo(_memoryInfo);
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
float[] mtx = new float[16];
surfaceTexture.getTransformMatrix(mtx);
mDirectDrawer.draw(mtx);
calculateFps();
//getAppMemorySize();
//getRunningAppProcessInfo();
//Log.v("onDrawFrame", "FPS: " + Math.round(fps) + ", availMem: " + Math.round(_memoryInfo.availMem / 1048576) + "MB");
private void getAppMemorySize()
ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
android.os.Debug.MemoryInfo[] memoryInfos = mActivityManager.getProcessMemoryInfo(new int[]android.os.Process.myPid());
int size = memoryInfos[0].dalvikPrivateDirty;
Log.w("getAppMemorySize", size / 1024 + " MB");
private void getRunningAppProcessInfo()
ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
//获得系统里正在运行的所有进程
List<RunningAppProcessInfo> runningAppProcessesList = mActivityManager.getRunningAppProcesses();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcessesList)
// 进程ID号
int pid = runningAppProcessInfo.pid;
// 用户ID
int uid = runningAppProcessInfo.uid;
// 进程名
String processName = runningAppProcessInfo.processName;
// 占用的内存
int[] pids = new int[] pid;
Debug.MemoryInfo[] memoryInfo = mActivityManager.getProcessMemoryInfo(pids);
int memorySize = memoryInfo[0].dalvikPrivateDirty;
System.out.println("processName="+processName+",currentPid: "+ "pid= " +android.os.Process.myPid()+"----------->"+pid+",uid="+uid+",memorySize="+memorySize+"kb");
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
surface = null;
surfaceTexture = null;
glSurfaceTex = Engine_CreateSurfaceTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
Log.d("GLES20Ext", "glSurfaceTex" + glSurfaceTex);
if (glSurfaceTex > 0)
surfaceTexture = new SurfaceTexture(glSurfaceTex);
surfaceTexture.setDefaultBufferSize(TEXTURE_WIDTH, TEXTURE_HEIGHT);
surface = new Surface(surfaceTexture);
addedWidgetView.setSurface(surface);
addedWidgetView.setSurfaceTexture(surfaceTexture);
//addedWidgetView.setSurfaceTexture(surfaceTexture);
mDirectDrawer = new DirectDrawer(glSurfaceTex);
float calculateFps()
frameCount++;
if (!b)
b = true;
previousTime = System.currentTimeMillis();
long intervalTime = System.currentTimeMillis() - previousTime;
if (intervalTime >= 1000)
b = false;
fps = frameCount / (intervalTime / 1000f);
frameCount = 0;
Log.w("calculateFps", "FPS: " + fps);
return fps;
int Engine_CreateSurfaceTexture(int width, int height)
/*
* Create our texture. This has to be done each time the surface is
* created.
*/
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
glSurfaceTex = textures[0];
if (glSurfaceTex > 0)
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, glSurfaceTex);
// Notice the use of GL_TEXTURE_2D for texture creation
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
return glSurfaceTex;
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
public class DirectDrawer
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"attribute vec2 inputTextureCoordinate;" +
"varying vec2 textureCoordinate;" +
"void main()" +
""+
"gl_Position = vPosition;"+
"textureCoordinate = inputTextureCoordinate;" +
"";
private final String fragmentShaderCode =
"#extension GL_OES_EGL_image_external : require\\n"+
"precision mediump float;" +
"varying vec2 textureCoordinate;\\n" +
"uniform samplerExternalOES s_texture;\\n" +
"void main() " +
" gl_FragColor = texture2D( s_texture, textureCoordinate );\\n" +
"";
private FloatBuffer vertexBuffer, textureVerticesBuffer;
private ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mTextureCoordHandle;
private short drawOrder[] = 0, 1, 2, 0, 2, 3 ; // order to draw vertices
// number of coordinates per vertex in this array
private static final int COORDS_PER_VERTEX = 2;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
static float squareCoords[] =
-1.0f, 0.0f,
-1.0f, -2.2f,
1.0f, -2.2f,
1.0f, 0.0f,
;
static float textureVertices[] =
0f, 0f,
0f, 1f,
1f, 1f,
1f, 0f,
;
private int texture;
public DirectDrawer(int texture)
this.texture = texture;
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * 4);
bb2.order(ByteOrder.nativeOrder());
textureVerticesBuffer = bb2.asFloatBuffer();
textureVerticesBuffer.put(textureVertices);
textureVerticesBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
public void draw(float[] mtx)
GLES20.glUseProgram(mProgram);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the <insert shape here> coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
// textureVerticesBuffer.clear();
// textureVerticesBuffer.put( transformTextureCoordinates(
// textureVertices, mtx ));
// textureVerticesBuffer.position(0);
GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureVerticesBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTextureCoordHandle);
private int loadShader(int type, String shaderCode)
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
private float[] transformTextureCoordinates( float[] coords, float[] matrix)
float[] result = new float[ coords.length ];
float[] vt = new float[4];
for ( int i = 0 ; i < coords.length ; i += 2 )
float[] v = coords[i], coords[i+1], 0 , 1 ;
Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);
result[i] = vt[0];
result[i+1] = vt[1];
return result;
步骤三:配置GLSurfaceView:
GLSurfaceView glSurfaceView = new GLSurfaceView(getApplicationContext());
// Setup the surface view for drawing to
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
glSurfaceView.setRenderer(renderer);
//glSurfaceView.setZOrderOnTop(true);
// Add our WebView to the Android View hierarchy
glSurfaceView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
以上是关于Android 原生的View渲染到OpenGL GLSurfaceView中,的主要内容,如果未能解决你的问题,请参考以下文章
Android 原生的View渲染到OpenGL GLSurfaceView中,
Android 原生的View渲染到OpenGL GLSurfaceView中,
把Android原生的View渲染到OpenGL Texture
把Android原生的View渲染到OpenGL Texture
我的OpenGL学习进阶之旅关于OpenGL ES 绘制中使用到的 Android中GLSurfaceView的两种渲染模式