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

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐