Android OpenGLES3绘图 - 使用映射缓冲区对象

Refrence

https://www.jianshu.com/p/e95c58198cba


OpenGL绘图一般是在主内存创建数据,计算后传给GPU内存,如果数据是频繁变化的,那么每一帧都要将数据用glBufferSubData方法复制到GPU。其实主内存数据可能是在一个固定的数组里,却要将这个数组反复复制到GPU。如果这个数组能放进GPU,在CPU计算完通知GPU刷新,就省去了复制的操作。

这就是映射缓冲区对象,它可以获取GPU中内存地址,或者可以认为是一段空的数组,操作这段数组就等于操作GPU内存中的数据。使用方法也很简单:用glMapBufferRange方法获取到数组后,在数组内操作,然后用glFlushMappedBufferRange方法通知GPU刷新。当然也有需要注意的地方。

之前写的Android OpenGLES3绘图 - 鱼群模拟,就是操作一段长度固定的数组,我们在这个项目上实验一下。

1 映射内存

原来分配GPU内存的操作是用ByteBuffer.allocate分配一段Native内存,通过vbo将它传给GPU。而glMapBufferRange方法返回了一个ByteBuffer对象,很容易认为这个ByteBuffer就是Native内存,可以直接使用。然而并不是,如果直接调用glMapBufferRange,返回的是null,必须要在分配完GPU内存后去调用。从“映射”这个名字也可以理解,它是将一段GPU内存映射出来,映射之前必须先给GPU分配内存。

还有Java的端序跟GPU分配的不一样,映射后要通过ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)转换才能使用。映射到ByteBuffer后就可以用glUnmapBuffer(GL_ARRAY_BUFFER)方法取消映射了,不影响后面使用这个ByteBuffer。

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

//        initPos();
        initAll();

        program = ShaderUtils.loadProgramGroup();

        // 分配内存空间,每个浮点型占4字节空间
        posBuffer = ByteBuffer
                .allocateDirect(2 * 4 * MAX_COUNT)
                .order(ByteOrder.nativeOrder());

        vao = new int[1];
        glGenVertexArrays(1, vao, 0);
        glBindVertexArray(vao[0]);

        vbo = new int[1];
        glGenBuffers(1, vbo, 0);
        glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
//        glBufferData(GL_ARRAY_BUFFER, vertices.length * 4, vertexBuffer, GL_STATIC_DRAW);
        glBufferData(GL_ARRAY_BUFFER, MAX_COUNT * 4 * 2, posBuffer, GL_STREAM_DRAW);

        if (useMapBuffer) {
            // 使用映射缓冲区对象,分配GPU内存直接操作
            ByteBuffer mapBuffer = (ByteBuffer) glMapBufferRange(GL_ARRAY_BUFFER, 0, MAX_COUNT * 4 * 2, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
            posBuffer = mapBuffer.order(ByteOrder.LITTLE_ENDIAN);
            glUnmapBuffer(GL_ARRAY_BUFFER);
        }
    }

2 通知刷新

原来对ByteBuffer数据的操作都不用改,在计算完绘制时不用通过glBufferSubData传输数据了,直接用glFlushMappedBufferRange通知GPU刷新就行了。这里加了一个useMapBuffer布尔值,对比使用映射缓冲区对象前后的区别。

    @Override
    public void onDrawFrame(GL10 gl) {
        super.onDrawFrame(gl);

//        update();
        updateAll();

        // Clear the color buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (useMapBuffer) {
            glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, MAX_COUNT * 4 * 2);
        } else {
            // 刷新vbo数据
            glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
            glBufferSubData(GL_ARRAY_BUFFER, 0, MAX_COUNT * 4 * 2,  posBuffer);
            glBindBuffer(GL_ARRAY_BUFFER, 0);
        }

从运行帧率上看,使用映射缓冲区对象后,性能有一点提升,但是并不明显。这跟具体项目有关,这个项目的性能瓶颈并不在此处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值