我还在努力禁用双缓冲或三缓冲。最后,我找到了解决方案。 (参见Automatic buffer clear while using OpenGL on Android)
- 原则上,此类配置与 OpenGL (ES) 无关。这是 EGL 的。
- 有一个名为
EGL_BUFFER_PRESERVED 的配置可以启用附加绘图。
- 要使用此配置,您可以选择直接使用
SurfaceView 而不是GLSurfaceView 来完全控制EGL,如@fadden 建议的above。或者,
- 您仍然可以使用
GLSurfaceView 和 setEGLConfigChooser 自定义 EGLConfigChooser 对象,然后在适当的时间调用 EGL14.eglSurfaceAttrib。
自定义 EGLConfigChooser 类:
启用EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT。
/**
* This class will choose a RGB_888 surface with or without a depth buffer.
* (Choosing a RGB_888 with a depth buffer is GLSurfaceView's default behavior.)
*
* In addition to the default behavior, it will enable EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT
* of EGL10.EGL_SURFACE_TYPE.
*
* cf. https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglChooseConfig.xhtml
*/
class SimpleConfigChooser(
private val eglContextClientVersion: Int, withDepthBuffer: Boolean = true,
) : GLSurfaceView.EGLConfigChooser {
private val value = IntArray(1)
private val redSize = 8
private val greenSize = 8
private val blueSize = 8
private val alphaSize = 0
private val depthSize = if (withDepthBuffer) 16 else 0
private val stencilSize = 0
private val configSpec = filterConfigSpec(intArrayOf(
EGL10.EGL_RED_SIZE, redSize,
EGL10.EGL_GREEN_SIZE, greenSize,
EGL10.EGL_BLUE_SIZE, blueSize,
EGL10.EGL_ALPHA_SIZE, alphaSize,
EGL10.EGL_DEPTH_SIZE, depthSize,
EGL10.EGL_STENCIL_SIZE, stencilSize,
EGL10.EGL_SURFACE_TYPE, (EGL10.EGL_WINDOW_BIT or EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT),
EGL10.EGL_NONE
))
private fun filterConfigSpec(configSpec: IntArray): IntArray {
if (eglContextClientVersion != 2 && eglContextClientVersion != 3) {
return configSpec
}
/* We know none of the subclasses define EGL_RENDERABLE_TYPE.
* And we know the configSpec is well formed.
*/
val len = configSpec.size
val newConfigSpec = IntArray(len + 2)
System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1)
newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE
if (eglContextClientVersion == 2) {
newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */
} else {
newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR /* EGL_OPENGL_ES3_BIT_KHR */
}
newConfigSpec[len + 1] = EGL10.EGL_NONE
return newConfigSpec
}
override fun chooseConfig(egl: EGL10, display: EGLDisplay): EGLConfig {
val numConfig = IntArray(1)
require(egl.eglChooseConfig(
display, configSpec, null, 0, numConfig
)) { "eglChooseConfig#1/2 failed" }
val numConfigs = numConfig[0]
require(numConfigs > 0) { "No configs match configSpec" }
val configs = arrayOfNulls<EGLConfig>(numConfigs)
require(egl.eglChooseConfig(
display, configSpec, configs, numConfigs, numConfig
)) { "eglChooseConfig#2/2 failed" }
return chooseConfig(egl, display, configs)
?: throw IllegalArgumentException("No config chosen")
}
private fun chooseConfig(
egl: EGL10, display: EGLDisplay, configs: Array<EGLConfig?>,
): EGLConfig? {
for (config in configs) {
if (config == null) {
continue
}
val d: Int = findConfigAttrib(egl, display, config,
EGL10.EGL_DEPTH_SIZE, 0)
val s: Int = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0)
if (d >= depthSize && s >= stencilSize) {
val r: Int = findConfigAttrib(egl, display, config,
EGL10.EGL_RED_SIZE, 0)
val g: Int = findConfigAttrib(egl, display, config,
EGL10.EGL_GREEN_SIZE, 0)
val b: Int = findConfigAttrib(egl, display, config,
EGL10.EGL_BLUE_SIZE, 0)
val a: Int = findConfigAttrib(egl, display, config,
EGL10.EGL_ALPHA_SIZE, 0)
if (r == redSize && g == greenSize
&& b == blueSize && a == alphaSize
) {
return config
}
}
}
return null
}
private fun findConfigAttrib(
egl: EGL10, display: EGLDisplay, config: EGLConfig, attribute: Int, defaultValue: Int,
): Int {
return if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
value[0]
} else defaultValue
}
}
在您的 GLSurfaceView.Renderer 子类中:
调用EGL14.eglSurfaceAttrib。
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
EGL14.eglSurfaceAttrib(
EGL14.eglGetCurrentDisplay(),
EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW),
EGL14.EGL_SWAP_BEHAVIOR, EGL14.EGL_BUFFER_PRESERVED
)
// some other work...
}
主活动:
将自定义EGLConfigChooser 设置为GLSurfaceView。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = MainActivityBinding.inflate(layoutInflater)
val EGL_CONTEXT_CLIENT_VERSION = 2
binding.glSurfaceView.setEGLContextClientVersion(
EGL_CONTEXT_CLIENT_VERSION
)
binding.glSurfaceView.setEGLConfigChooser(
SimpleConfigChooser(EGL_CONTEXT_CLIENT_VERSION)
)
binding.glSurfaceView.setRenderer(Renderer()) // this should be the last
setContentView(binding.root)
// some other work...
}