android opengles从帧缓存高效拷贝数据
代码】android opengles从帧缓存高效拷贝数据。
·
1.glReadPixels直接拷贝到CPU
public int[] cutRectToBmpDataPure(RectF drawRect) {
IntBuffer ib;
RectF rectF = new RectF(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
//android UI坐标和GL坐标的反转
float temp1 = rectF.top;
rectF.top = rectF.bottom;
rectF.bottom = temp1;
int rectWidth = (int) Math.abs(rectF.right - rectF.left);
int rectHeight = (int) Math.abs(rectF.top - rectF.bottom);
if (preWidth != rectWidth || preHeight != rectHeight) {
ib = IntBuffer.allocate(rectWidth * rectHeight);
}
preWidth = rectWidth;
preHeight = rectHeight;
GLES30.glReadPixels((int) rectF.left, (int) rectF.bottom, rectWidth, rectHeight, GL_RGBA, GL_UNSIGNED_BYTE,
ib);
return ib.array();
}
2.使用pbo内存映射方式(貌似pbo不是这么用的,效率和方式1相当)
public int[] DownloadPixels(RectF drawRect) {
IntBuffer ib;
RectF rectF = new RectF(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
//android UI坐标和GL坐标的反转
float temp1 = rectF.top;
rectF.top = rectF.bottom;
rectF.bottom = temp1;
int rectWidth = (int) Math.abs(rectF.right - rectF.left);
int rectHeight = (int) Math.abs(rectF.top - rectF.bottom);
if (preWidth != rectWidth || preHeight != rectHeight) {
ib = IntBuffer.allocate(rectWidth * rectHeight);
}
preWidth = rectWidth;
preHeight = rectHeight;
int[] m_DownloadPboIds= new int[]{GLES30.GL_NONE};
int dataSize = (int) preWidth * (int) preHeight * 4;
GLES30.glGenBuffers(1, m_DownloadPboIds,0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[0]);
GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, dataSize, null, GLES30.GL_STREAM_READ);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[0]);
GLES30.glReadPixels((int) rectF.left, (int) rectF.bottom, rectWidth, rectHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[0]);
Buffer mappedBuffer = GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, dataSize, GLES30.GL_MAP_READ_BIT);
ByteBuffer byteBuf = (ByteBuffer)mappedBuffer;
byteBuf.order(ByteOrder.nativeOrder());
IntBuffer floatBuf = byteBuf.asIntBuffer();
ib.clear();
ib.put(floatBuf);
GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
GLES30.glDeleteBuffers(1, m_DownloadPboIds,0);
return ib.array();
}
3.顶点缓冲内存映射方式
(1)创建顶点缓存
glGenBuffers(1, &readBuffer);
glBindBuffer(GL_ARRAY_BUFFER, readBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * FRAME_WIDTH * FRAME_HEIGHT * 3, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
(2)把帧缓存数据读取到顶点缓冲readBuffer
//缓存绑定
glBindBuffer(GL_PIXEL_PACK_BUFFER, readBuffer);
//输出到readBuffer上
glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_RGB, GL_FLOAT, NULL);
(3)把readBuffer中的数据映射到内存中
//映射
float *data = (float *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
//完成后解除映射
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
代码(实际跟方式2一样,用法不对)
public int[] DownloadPixels2(RectF drawRect) {
RectF rectF = new RectF(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
//android UI坐标和GL坐标的反转
float temp1 = rectF.top;
rectF.top = rectF.bottom;
rectF.bottom = temp1;
int rectWidth = (int) Math.abs(rectF.right - rectF.left);
int rectHeight = (int) Math.abs(rectF.top - rectF.bottom);
if (preWidth != rectWidth || preHeight != rectHeight) {
ib = IntBuffer.allocate(rectWidth * rectHeight);
}
preWidth = rectWidth;
preHeight = rectHeight;
int dataSize = (int) rectWidth * (int) rectHeight * 4;
int[] readBuffer=new int[1];
GLES30.glGenBuffers(1, readBuffer,0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, readBuffer[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, dataSize, null, GLES30.GL_DYNAMIC_DRAW);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, readBuffer[0]);
GLES30.glReadPixels((int) rectF.left, (int) rectF.bottom, rectWidth, rectHeight, GL_RGBA, GLES30.GL_UNSIGNED_BYTE, 0);
//GLES32.glMapBuffer(GLES30.GL_PIXEL_PACK_BUFFER); //这个接口不支持,用下面的代替
Buffer mappedBuffer = GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, dataSize, GLES30.GL_MAP_READ_BIT);
ByteBuffer byteBuf = (ByteBuffer)mappedBuffer;
byteBuf.order(ByteOrder.nativeOrder());
IntBuffer floatBuf = byteBuf.asIntBuffer();
ib.clear();
ib.put(floatBuf);
GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);
GLES30.glDeleteBuffers(1, readBuffer,0);
return ib.array();
}
最终改成异步读取缓存方案
封装为工具
public class GlBufferUtils {
private int[] m_DownloadPboIds= new int[]{GLES30.GL_NONE};
public Buffer m_mappedBuffer=null;
public int m_width;
public int m_height;
public GlBufferUtils(int left, int bottom,int width,int height){
m_width=width;
m_height=height;
int dataSize = width * height * 4;
GLES30.glGenBuffers(1, m_DownloadPboIds,0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[0]);
GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, dataSize, null, GLES30.GL_STREAM_READ);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[0]);
GLES30.glReadPixels( left, bottom, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[0]);
m_mappedBuffer = GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, dataSize, GLES30.GL_MAP_READ_BIT);
GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
}
public Buffer getBuffer(){
return m_mappedBuffer;
}
public int[] getIntArray(){
IntBuffer ib = IntBuffer.allocate(m_width * m_height);
ByteBuffer byteBuf = (ByteBuffer)m_mappedBuffer;
byteBuf.order(ByteOrder.nativeOrder());
IntBuffer floatBuf = byteBuf.asIntBuffer();
ib.clear();
ib.put(floatBuf);
return ib.array();
}
public void destory(){
GLES30.glDeleteBuffers(1, m_DownloadPboIds,0);
}
}
调用
public GlBufferUtils readPixelsSync(RectF drawRect) {
RectF rectF = new RectF(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
//android UI坐标和GL坐标的反转
float temp1 = rectF.top;
rectF.top = rectF.bottom;
rectF.bottom = temp1;
int rectWidth = (int) Math.abs(rectF.right - rectF.left);
int rectHeight = (int) Math.abs(rectF.top - rectF.bottom);
GlBufferUtils mgBufferMap=new GlBufferUtils((int) rectF.left, (int) rectF.bottom, rectWidth, rectHeight);
return mgBufferMap;
}
然后在另一个线程读取像素数据
int[] data=glBufferUtils.getIntArray();
...
//读取完数据删除gl缓存
glBufferUtils.destory();
https://blog.csdn.net/Kennethdroid/article/details/103931627
https://blog.csdn.net/niu2212035673/article/details/80251949
更多推荐
已为社区贡献8条内容
所有评论(0)