Reputation: 11
I was trying to use opengl es 2.0 in android. I use GLSurfaceView as my main view. Here is the question. I want to draw several points in a row. That is when I click on the view, I draw one point and call requestRender. But I dont want to store all the point I triggered because there will be plenty of them. So my onDrawFrame()
only have one sentence, maybe like this:
GLES20.glDrawArrays(GLES20.GL_POINTS, 8, 1);
The question is, this logic works well on my android virtual machine, but all the things I've draw just disappear when I draw a new point.
Is there a way to retain all the points I've draw on GLSurfaceView and then keep on drawing without saving all the points?
Upvotes: 1
Views: 655
Reputation: 12478
I was also struggling to disable double- or triple- buffering. Finally, I found a solution. (cf. Automatic buffer clear while using OpenGL on Android)
EGL_BUFFER_PRESERVED
which enables additive drawing.SurfaceView
directly other than GLSurfaceView
to fully control over EGL like @fadden suggested above. Or,GLSurfaceView
and setEGLConfigChooser
a custom EGLConfigChooser object to it, then invoke EGL14.eglSurfaceAttrib
at an appropriate timing.Enabling 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
subclass:Invoke 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...
}
Set the custom EGLConfigChooser
to 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...
}
Upvotes: 0
Reputation: 52313
You need to redraw the entire screen every frame. The output is usually double- or triple-buffered, so you can't rely on the availability of the previous contents. Always start with a glClear()
call.
One way to do what you want is to render onto an FBO, then blit the FBO to the screen. You can find an example of this in Grafika's "record GL app" activity, which is actually using it so it can render each frame twice (once to the screen, once to the video encoder), and in various examples on the web. The basic idea is that you're rendering onto a GLES texture, rather than directly into the Surface, so there's no double-buffering to contend with.
Upvotes: 1
Reputation: 1
If you have used GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
in onFrameRedraw()
method, remove it and instead, use it in onSurfaceCreated()
method of the Renderer.
Upvotes: 0