OpenGL ES 高级进阶:fence同步

栏目: 后端 · 发布时间: 5年前

内容简介:大家好,这是我的今天给大家介绍因此,一般情况下我们调用

大家好,这是我的 OpenGL ES 高级进阶系列文章,在我的 github 上有一个与本系列文章对应的项目,欢迎关注,链接: github.com/kenneycode/…

今天给大家介绍 OpenGL ES 3.0 的一个特性 fence ,它可以用来同步 OpenGL 命令,在多线程编程时很有用,我之前的一篇文章《OpenGL ES 命令队列及glFlush/glFinish》中有说到, OpenGL 命令的执行是在 GPU 上的,我们调用 OpenGL 方法实际上是往 OpenGL 的命令队列里面插入命令, GPU 从命令中取出命令执行。

因此,一般情况下我们调用 OpenGL 方法后,并不是马上有效果的,如果要某处确保之前的 OpenGL 执行完,就需要用到 glFinish ,但 glFinish 只能保证本线程对应的命令队列中的命令执行完,这就意味着不能在一个线程中等待另一个线程的 OpenGL 命令执行完,这就有很大的限制,回想我们在 CPU 上的同步操作,例如我们在一个线程中wait,在另一个线程中notify,这很容易实现在一个线程中等待另一个线程的指定任务执行完成,这也是我们很常用的操作,但在对于 GPU ,无法用 glFinish 来实现类似的逻辑,实际上,在 OpenGL ES 3.0 以前,是无法实现的。

到了 OpenGL ES 3.0 ,我们可以用 fence 实现,使用越来也很简单,就是在一个线程中插入一个 fence ,然后在另一个线程中就可以去等待这个 fence ,我画了一张图:

OpenGL ES 高级进阶:fence同步

例如我们有这样一种逻辑,在 GLThread 0 中渲染一个纹理,在另一个线程 GLThread 1 中将这个纹理拿去使用,那就需要确保在 GLThread 1 使用这个纹理时, GLThread 0 对这个纹理的渲染已经完成,有了 fence 后,我们可以在 GLThread 0 渲染操作之后插入一个 fence ,然后在 GLThread 1 要使用这个纹理时去等这个 fence

我们来看看代码,先看看插入 fence 的代码:

val fenceSyncObject = GLES30.glFenceSync(GLES30.GL_SYNC_GPU_COMMANDS_COMPLETE, 0)
复制代码

这个方法调用后会往当前线程的命令队列中插入一个 fence 并返回一个 long 型变量来代码这个 fence 同步对象,以便于其它地方去等待它,有2个方法可以用于等待, glWaitSyncglClientWaitSync ,它们的差别是 glWaitSync 是在 GPU 上等待, glClientWaitSync 是在 CPU 上等待。

来看看我们有例子代码,在这个例子中,我们在一个线程中渲染一张图到一个纹理同时到屏幕上,在另一个线程中将这个纹理读出来显示到屏幕的右下角的一个 ImageView 上:

override fun onDrawFrame(gl: GL10?) {
            
    ...
    
    // 渲染到纹理上
    // Render to texture
    GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, textureCoordinateData.size / VERTEX_COMPONENT_COUNT)

    // 向OpenGL的Command Buffer中插入一个fence
    // Insert a fence into the OpenGL command buffer
    val fenceSyncObject = GLES30.glFenceSync(GLES30.GL_SYNC_GPU_COMMANDS_COMPLETE, 0)

    // 在另一个线程中读取当前线程的渲染结果
    // Read the render result in the other thread
    otherThreadHandler.post {
        if (!flag) {

            // 等待fence前的OpenGL命令执行完毕
            // Waiting for completion of the OpenGL commands before our fence
            GLES30.glWaitSync(fenceSyncObject, 0, GLES30.GL_TIMEOUT_IGNORED)

            // 删除fence同步对象
            // Delete the fence sync object
            GLES30.glDeleteSync(fenceSyncObject)

            val frameBuffers = IntArray(1)
            GLES30.glGenFramebuffers(frameBuffers.size, frameBuffers, 0)
            GLES30.glActiveTexture(GLES30.GL_TEXTURE1)
            GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, sharedTexture)
            GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, frameBuffers[0])
            GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, sharedTexture, 0)
            val buffer = ByteBuffer.wrap(ByteArray(glSurfaceViewWidth * glSurfaceViewHeight * 4))
            GLES30.glReadPixels(0, 0, glSurfaceViewWidth, glSurfaceViewHeight, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, buffer)
            GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
            val bitmap = Bitmap.createBitmap(glSurfaceViewWidth, glSurfaceViewHeight, Bitmap.Config.ARGB_8888)
            buffer.position(0)
            bitmap.copyPixelsFromBuffer(buffer)
            flag = true

            // 将读取到的渲染结果显示到一个ImageView上
            // Display the read render result on a ImageView
            imageView.post {
                imageView.setImageBitmap(bitmap)
            }
        }

    }

    // 将frame buffer绑回0号,将渲染结果同时也显示到屏幕上
    // Bind frame buffer to 0# and also render the result on screen
    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)

    GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexture)

    GLES30.glClearColor(0.9f, 0.9f, 0.9f, 1f)

    // 清屏
    // Clear the screen
    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

    // 设置视口,这里设置为整个GLSurfaceView区域
    // Set the viewport to the full GLSurfaceView
    GLES30.glViewport(0, 0, glSurfaceViewWidth, glSurfaceViewHeight)

    GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexData.size / VERTEX_COMPONENT_COUNT)
}
复制代码

加了 fence 后就能保证在另一个线程中读出的时候,图片纹理已经渲染完成了,如果不加 fence ,可能会观察到读出来的纹理是残缺不全的,渲染操作越是复杂,越是可能观察到,因为读的时候还来不及渲染完,在这个例子中,我做了一个模糊操作,让渲染操作稍微变得复杂。

下面是这个例子的效果:

OpenGL ES 高级进阶:fence同步

代码在我 githubOpenGLESPro 项目中,本文对应的是 SampleFenceSync ,项目链接: github.com/kenneycode/…

感谢阅读!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大型网站技术架构演进与性能优化

大型网站技术架构演进与性能优化

许令波 / 电子工业出版社 / 2018-6 / 79

《大型网站技术架构演进与性能优化》从一名亲历者的角度,阐述了一个网站在业务量飞速发展的过程中所遇到的技术转型等各种问题及解决思路。从技术发展上看,网站经历了Web应用系统从分布式、无线多端、中台到国际化的改造;在解决大流量问题的方向上,涉及了从端的优化到管道到服务端甚至到基础环境优化的各个层面。 《大型网站技术架构演进与性能优化》总结的宝贵经验教训可以帮助读者了解当网站遇到类似问题时,应如何......一起来看看 《大型网站技术架构演进与性能优化》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具