解决android opengl glReadPixels 慢的问题
由于android的gpu跟cpu内存是分离的,导致数据拷贝的过程中会非常慢,网上资料相对较少,下面是我解决这个问题的一点心的,使用PBO代码如下
1. 初始化纹理方法
public static int loadTexture(final Bitmap img, final int usedTexId, int i) {
if(img == null)
return NO_TEXTURE;
// ByteBuffer img_buffer = ByteBuffer.allocate(img.getByteCount());
// img.copyPixelsToBuffer(img_buffer);
ByteBuffer pbo_point = null;
int textures[] = new int[1];
if (usedTexId == NO_TEXTURE) {
GLES30.glGenTextures(1, textures, 0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textures[0]);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glGenBuffers(1, pbo);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, pbo.get(0));
GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER,width*height*4, null, GLES30.GL_DYNAMIC_READ);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, img, 0);
}
else {
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, usedTexId);
// GLUtils.texSubImage2D(GLES30.GL_TEXTURE_2D, 0, 0, 0, img);
textures[0] = usedTexId;
}
return textures[0];
}
2. 初始化PBO
public static int loadFramebuffer(int texture, int width,int height){
IntBuffer framebuffer = IntBuffer.allocate(1);
IntBuffer depthRenderbuffer = IntBuffer.allocate(1);
IntBuffer max = IntBuffer.allocate(10);
int temp = 0;
GLES30.glGetIntegerv(GLES30.GL_MAX_RENDERBUFFER_SIZE, max);
temp = max.get(0);
if (temp <= width && temp <= height)
{
return -1;
}
GLES30.glGenFramebuffers(1, framebuffer);
GLES30.glGenRenderbuffers(1, depthRenderbuffer);
GLES30.glBindRenderbuffer(GLES30.GL_RENDERBUFFER, depthRenderbuffer.get(0));
GLES30.glRenderbufferStorage(GLES30.GL_RENDERBUFFER, GLES30.GL_RGBA, width, height);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, framebuffer.get(0));
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, texture, 0);
GLES30.glFramebufferRenderbuffer(GLES30.GL_FRAMEBUFFER,GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_RENDERBUFFER, depthRenderbuffer.get(0));
int status = 0;
status = GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER);
if (status == GLES30.GL_FRAMEBUFFER_COMPLETE){
Log.d(TAG,"frame buffer init ok!!!!!!!");
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
GLES30.glDeleteRenderbuffers(1, depthRenderbuffer);
GLES30.glDeleteFramebuffers(1, framebuffer);
return framebuffer.get();
}
Log.d(TAG,"frame buffer init file!!!!!!!");
return -1;
}
3. surface creat 初始化
public void onSurfaceCreated ( GL10 glUnused, EGLConfig config )
{
String vShaderStr =
"attribute vec4 position;\n" +
"attribute vec4 inputTextureCoordinate;\n" +
" \n" +
"varying vec2 textureCoordinate;\n" +
" \n" +
"void main()\n" +
"{\n" +
" gl_Position = position;\n" +
" textureCoordinate = inputTextureCoordinate.xy;\n" +
"}";
String fShaderStr =
"precision highp float; \n"
+ "varying highp vec2 textureCoordinate;\n"
+ "uniform sampler2D inputImageTexture;\n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D(inputImageTexture, textureCoordinate); \n"
+ "} \n";
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the vertex/fragment shaders
vertexShader = LoadShader ( GLES30.GL_VERTEX_SHADER, vShaderStr );
fragmentShader = LoadShader ( GLES30.GL_FRAGMENT_SHADER, fShaderStr );
// Create the program object
programObject = GLES30.glCreateProgram();
if ( programObject == 0 )
{
return;
}
GLES30.glAttachShader ( programObject, vertexShader );
GLES30.glAttachShader ( programObject, fragmentShader );
// Bind vPosition to attribute 0
GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );
// Link the program
GLES30.glLinkProgram ( programObject );
// Check the link status
GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );
if ( linked[0] == 0 )
{
Log.e ( TAG, vShaderStr );
Log.e ( TAG, fShaderStr );
Log.e ( TAG, "Error linking program:" );
Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
GLES30.glDeleteProgram ( programObject );
return;
}
// Store the program object
mProgramObject = programObject;
mGLAttribPosition = GLES30.glGetAttribLocation(programObject, "position");
mGLUniformTexture = GLES30.glGetUniformLocation(programObject, "inputImageTexture");
mGLAttribTextureCoordinate = GLES30.glGetAttribLocation(programObject,
"inputTextureCoordinate");
Log.d(TAG,"id = " + color_id + "mGLUniformTexture= " + mGLUniformTexture);
// GLES30.glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
}
4. 最后使用pbo 画出来
public void onDrawFrame ( GL10 glUnused )
{
index++;
mTextureId = loadTexture(bitmap,mTextureId,0);
// Set the viewport
GLES30.glViewport ( 0, 0, width ,height);
// Clear the color buffer
GLES30.glClearColor(0.0f,0.0f,0.0f,0.0f);
GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT );
// Use the program object
GLES30.glUseProgram ( mProgramObject );
mVertices.position(0);
GLES30.glVertexAttribPointer ( mGLAttribPosition, 3, GLES30.GL_FLOAT, false, 0, mVertices );
GLES30.glEnableVertexAttribArray ( mGLAttribPosition );
mGLTextureBuffer.position(0);
GLES30.glVertexAttribPointer ( mGLAttribTextureCoordinate, 2, GLES30.GL_FLOAT, false, 0, mGLTextureBuffer );
GLES30.glEnableVertexAttribArray ( mGLAttribTextureCoordinate );
//
if (mTextureId >= 0)
{
//loadFramebuffer(mTextureId,width,height);
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId);
GLES30.glUniform1i(mGLUniformTexture, 0);
}
GLES30.glDrawArrays ( GLES30.GL_TRIANGLE_STRIP, 0, 4 );
Log.d("jni", "刷新时间");
return;
}
总结:虽然使用一个PBO但是效果改变不是很明显,因为单个PBO传输还是需要等待的,假如使用2个pbo,这样错开接收就会使效率大大提高,请看下篇使用2个PBO速度慢的问题。