GLRenderer
class GLRenderer
Class responsible for coordination of requests to render into surfaces using OpenGL. This creates a backing thread to handle EGL dependencies and draw leveraging OpenGL across multiple android.view.Surface
instances that can be attached and detached throughout the lifecycle of an application. Usage of this class is recommended to be done on the UI thread.
Summary
Nested types |
---|
interface GLRenderer.EGLContextCallback Callbacks invoked when the GL dependencies are created and destroyed. |
interface GLRenderer.RenderCallback Interface used for creating an |
class GLRenderer.RenderTarget Handle to a |
Public constructors |
---|
GLRenderer( |
Public functions |
|
---|---|
GLRenderer.RenderTarget |
attach(surfaceView: SurfaceView, renderer: GLRenderer.RenderCallback) Adds the |
GLRenderer.RenderTarget |
attach(textureView: TextureView, renderer: GLRenderer.RenderCallback) Adds the |
GLRenderer.RenderTarget |
attach( Adds the |
GLRenderer.RenderTarget |
createRenderTarget( Creates a new |
Unit |
detach( Removes the corresponding |
Unit |
Queue a |
Boolean |
Determines if the GLThread has been started. |
Unit |
Add an |
Unit |
requestRender( Mark the corresponding surface session with the given token as dirty to schedule a call to RenderCallback#onDrawFrame. |
Unit |
resize( Resize the corresponding surface associated with the RenderTarget to the specified width and height and re-render. |
Unit |
Starts the GLThread. |
Unit |
stop(cancelPending: Boolean, onStop: ((GLRenderer) -> Unit)?) Stop the corresponding GL thread. |
Unit |
Remove |
Public constructors
GLRenderer
GLRenderer(
eglSpecFactory: () -> EGLSpec = { EGLSpec.V14 },
eglConfigFactory: EGLManager.() -> EGLConfig = { // 8 bit channels should always be supported loadConfig(EGLConfigAttributes.RGBA_8888) ?: throw IllegalStateException("Unable to obtain config for 8 bit EGL " + "configuration") }
)
Parameters | |
---|---|
eglSpecFactory: () -> EGLSpec = { EGLSpec.V14 } |
Callback invoked to determine the EGL spec version to use for EGL management. This is invoked on the GL Thread |
eglConfigFactory: EGLManager.() -> EGLConfig = {
// 8 bit channels should always be supported
loadConfig(EGLConfigAttributes.RGBA_8888)
?: throw IllegalStateException("Unable to obtain config for 8 bit EGL " +
"configuration")
} |
Callback invoked to determine the appropriate EGLConfig used to create the EGL context. This is invoked on the GL Thread |
Public functions
attach
fun attach(surfaceView: SurfaceView, renderer: GLRenderer.RenderCallback): GLRenderer.RenderTarget
Adds the android.view.Surface
provided by the given SurfaceView
to be managed by the backing thread.
A corresponding EGLSurface
is created on the GLThread as well as a callback for rendering into the surface through RenderCallback
.
This method automatically configures a SurfaceHolder.Callback
used to attach the android.view.Surface
when the underlying SurfaceHolder
that contains the surface is available. Similarly this surface will be detached from GLRenderer
when the surface provided by the SurfaceView
is destroyed (i.e. SurfaceHolder.Callback.surfaceDestroyed
is called.
If the android.view.Surface
is already available by the time this method is invoked, it is attached synchronously.
Parameters | |
---|---|
surfaceView: SurfaceView |
SurfaceView that provides the surface to be rendered by the backing thread |
renderer: GLRenderer.RenderCallback |
callbacks used to create a corresponding |
Returns | |
---|---|
GLRenderer.RenderTarget |
|
Throws | |
---|---|
kotlin.IllegalStateException |
If this method was called when the GLThread has not started (i.e. start has not been called) |
attach
fun attach(textureView: TextureView, renderer: GLRenderer.RenderCallback): GLRenderer.RenderTarget
Adds the android.view.Surface
provided by the given TextureView
to be managed by the backing thread.
A corresponding EGLSurface
is created on the GLThread as well as a callback for rendering into the surface through RenderCallback
.
This method automatically configures a TextureView.SurfaceTextureListener
used to create a android.view.Surface
when the underlying SurfaceTexture
is available. Similarly this surface will be detached from GLRenderer
if the underlying SurfaceTexture
is destroyed (i.e. TextureView.SurfaceTextureListener.onSurfaceTextureDestroyed
is called.
If the SurfaceTexture
is already available by the time this method is called, then it is attached synchronously.
Parameters | |
---|---|
textureView: TextureView |
TextureView that provides the surface to be rendered into on the GLThread |
renderer: GLRenderer.RenderCallback |
callbacks used to create a corresponding |
Returns | |
---|---|
GLRenderer.RenderTarget |
|
Throws | |
---|---|
kotlin.IllegalStateException |
If this method was called when the GLThread has not started (i.e. start has not been called) |
attach
fun attach(
surface: Surface,
width: Int,
height: Int,
renderer: GLRenderer.RenderCallback
): GLRenderer.RenderTarget
Adds the android.view.Surface
to be managed by the GLThread. A corresponding EGLSurface
is created on the GLThread as well as a callback for rendering into the surface through RenderCallback
. Unlike the other attach
methods that consume a SurfaceView
or TextureView
, this method does not handle any lifecycle callbacks associated with the target surface. Therefore it is up to the consumer to properly setup/teardown resources associated with this surface.
Parameters | |
---|---|
surface: Surface |
Target surface to be managed by the backing thread |
width: Int |
Desired width of the |
height: Int |
Desired height of the |
renderer: GLRenderer.RenderCallback |
Callbacks used to create a corresponding |
Returns | |
---|---|
GLRenderer.RenderTarget |
|
Throws | |
---|---|
kotlin.IllegalStateException |
If this method was called when the GLThread has not started (i.e. start has not been called) |
createRenderTarget
fun createRenderTarget(
width: Int,
height: Int,
renderer: GLRenderer.RenderCallback
): GLRenderer.RenderTarget
Creates a new RenderTarget
without a corresponding android.view.Surface
. This avoids creation of an EGLSurface
which is useful in scenarios where only rendering to a frame buffer object is required.
Parameters | |
---|---|
width: Int |
Desired width of the |
height: Int |
Desired height of the |
renderer: GLRenderer.RenderCallback |
Callbacks used to issue OpenGL commands to the |
Returns | |
---|---|
GLRenderer.RenderTarget |
|
Throws | |
---|---|
kotlin.IllegalStateException |
If this method was called when the GLThread has not started (i.e. start has not been called) |
detach
fun detach(
target: GLRenderer.RenderTarget,
cancelPending: Boolean,
@WorkerThread onDetachComplete: ((GLRenderer.RenderTarget) -> Unit)? = null
): Unit
Removes the corresponding RenderTarget
from management of the GLThread. This destroys the EGLSurface associated with this surface and subsequent requests to render into the surface with the provided token are ignored.
If the cancelPending
flag is set to true, any queued request to render that has not started yet is cancelled. However, if this is invoked in the middle of the frame being rendered, it will continue to process the current frame.
Additionally if this flag is false, all pending requests to render will be processed before the RenderTarget
is detached.
Note the detach operation will only occur if the GLRenderer is started, that is if isRunning
returns true. Otherwise this is a no-op. GLRenderer will automatically detach all RenderTarget
instances as part of its teardown process.
execute
fun execute(runnable: Runnable): Unit
Queue a Runnable
to be executed on the GL rendering thread. Note it is important that this Runnable
does not block otherwise it can stall the GL thread. The EGLContext will be created after start
is invoked and before the runnable is executed.
Parameters | |
---|---|
runnable: Runnable |
Runnable to be executed |
isRunning
fun isRunning(): Boolean
Determines if the GLThread has been started. That is start
has been invoked on this GLRenderer instance without a corresponding call to stop
.
registerEGLContextCallback
fun registerEGLContextCallback(callback: GLRenderer.EGLContextCallback): Unit
Add an EGLContextCallback
to receive callbacks for construction and destruction of EGL dependencies.
These callbacks are invoked on the backing thread.
requestRender
fun requestRender(
target: GLRenderer.RenderTarget,
onRenderComplete: ((GLRenderer.RenderTarget) -> Unit)? = null
): Unit
Mark the corresponding surface session with the given token as dirty to schedule a call to RenderCallback#onDrawFrame. If there is already a queued request to render into the provided surface with the specified token, this request is ignored.
Note the render operation will only occur if the GLRenderer is started, that is if isRunning
returns true. Otherwise this is a no-op.
Parameters | |
---|---|
target: GLRenderer.RenderTarget |
RenderTarget to be re-rendered |
onRenderComplete: ((GLRenderer.RenderTarget) -> Unit)? = null |
Optional callback invoked on the backing thread after the frame has been rendered. |
resize
fun resize(
target: GLRenderer.RenderTarget,
width: Int,
height: Int,
onResizeComplete: ((GLRenderer.RenderTarget) -> Unit)? = null
): Unit
Resize the corresponding surface associated with the RenderTarget to the specified width and height and re-render. This will destroy the EGLSurface created by RenderCallback.onSurfaceCreated
and invoke it again with the updated dimensions. An optional callback is invoked on the backing thread after the resize operation is complete.
Note the resize operation will only occur if the GLRenderer is started, that is if isRunning
returns true. Otherwise this is a no-op.
Parameters | |
---|---|
target: GLRenderer.RenderTarget |
RenderTarget to be resized |
width: Int |
Updated width of the corresponding surface |
height: Int |
Updated height of the corresponding surface |
onResizeComplete: ((GLRenderer.RenderTarget) -> Unit)? = null |
Optional callback invoked on the backing thread when the resize operation is complete |
start
fun start(name: String = "GLThread"): Unit
Starts the GLThread. After this method is called, consumers can attempt to attach android.view.Surface
instances through attach
as well as schedule content to be drawn through requestRender
Parameters | |
---|---|
name: String = "GLThread" |
Optional name to provide to the GLThread |
Throws | |
---|---|
kotlin.IllegalStateException |
if EGLConfig with desired attributes cannot be created |
stop
fun stop(cancelPending: Boolean, onStop: ((GLRenderer) -> Unit)? = null): Unit
Stop the corresponding GL thread. This destroys all EGLSurfaces as well as any other EGL dependencies. All queued requests that have not been processed yet are cancelled.
Note the stop operation will only occur if the GLRenderer was previously started, that is isRunning
returns true. Otherwise this is a no-op.
Parameters | |
---|---|
cancelPending: Boolean |
If true all pending requests and cancelled and the backing thread is torn down immediately. If false, all pending requests are processed first before tearing down the backing thread. Subsequent requests made after this call are ignored. |
onStop: ((GLRenderer) -> Unit)? = null |
Optional callback invoked on the backing thread after it is torn down. |
unregisterEGLContextCallback
fun unregisterEGLContextCallback(callback: GLRenderer.EGLContextCallback): Unit
Remove EGLContextCallback
to no longer receive callbacks for construction and destruction of EGL dependencies.
These callbacks are invoked on the backing thread