GLRenderer


public final 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

Callbacks invoked when the GL dependencies are created and destroyed.

public interface GLRenderer.RenderCallback

Interface used for creating an EGLSurface with a user defined configuration from the provided surface as well as a callback used to render content into the surface for a given frame

public final class GLRenderer.RenderTarget

Handle to a android.view.Surface that is given to GLRenderer to handle rendering.

Public constructors

GLRenderer(
    @NonNull Function0<@NonNull EGLSpec> eglSpecFactory,
    @ExtensionFunctionType @NonNull Function1<@NonNull EGLManager, @NonNull EGLConfig> eglConfigFactory
)

Public methods

final @NonNull GLRenderer.RenderTarget
attach(
    @NonNull SurfaceView surfaceView,
    @NonNull GLRenderer.RenderCallback renderer
)

Adds the android.view.Surface provided by the given SurfaceView to be managed by the backing thread.

final @NonNull GLRenderer.RenderTarget
attach(
    @NonNull TextureView textureView,
    @NonNull GLRenderer.RenderCallback renderer
)

Adds the android.view.Surface provided by the given TextureView to be managed by the backing thread.

final @NonNull GLRenderer.RenderTarget
attach(
    @NonNull Surface surface,
    int width,
    int height,
    @NonNull GLRenderer.RenderCallback renderer
)

Adds the android.view.Surface to be managed by the GLThread.

final @NonNull GLRenderer.RenderTarget
createRenderTarget(
    int width,
    int height,
    @NonNull GLRenderer.RenderCallback renderer
)

Creates a new RenderTarget without a corresponding android.view.Surface.

final void
detach(
    @NonNull GLRenderer.RenderTarget target,
    boolean cancelPending,
    @WorkerThread Function1<@NonNull GLRenderer.RenderTargetUnit> onDetachComplete
)

Removes the corresponding RenderTarget from management of the GLThread.

final void

Queue a Runnable to be executed on the GL rendering thread.

final boolean

Determines if the GLThread has been started.

final void

Add an EGLContextCallback to receive callbacks for construction and destruction of EGL dependencies.

final void
requestRender(
    @NonNull GLRenderer.RenderTarget target,
    Function1<@NonNull GLRenderer.RenderTargetUnit> onRenderComplete
)

Mark the corresponding surface session with the given token as dirty to schedule a call to RenderCallback#onDrawFrame.

final void
resize(
    @NonNull GLRenderer.RenderTarget target,
    int width,
    int height,
    Function1<@NonNull GLRenderer.RenderTargetUnit> onResizeComplete
)

Resize the corresponding surface associated with the RenderTarget to the specified width and height and re-render.

final void

Starts the GLThread.

final void
stop(boolean cancelPending, Function1<@NonNull GLRendererUnit> onStop)

Stop the corresponding GL thread.

final void

Remove EGLContextCallback to no longer receive callbacks for construction and destruction of EGL dependencies.

Public constructors

GLRenderer

public GLRenderer(
    @NonNull Function0<@NonNull EGLSpec> eglSpecFactory,
    @ExtensionFunctionType @NonNull Function1<@NonNull EGLManager, @NonNull EGLConfig> eglConfigFactory
)
Parameters
@NonNull Function0<@NonNull EGLSpec> eglSpecFactory

Callback invoked to determine the EGL spec version to use for EGL management. This is invoked on the GL Thread

@ExtensionFunctionType @NonNull Function1<@NonNull EGLManager, @NonNull EGLConfig> eglConfigFactory

Callback invoked to determine the appropriate EGLConfig used to create the EGL context. This is invoked on the GL Thread

Public methods

attach

Added in 1.0.2
public final @NonNull GLRenderer.RenderTarget attach(
    @NonNull SurfaceView surfaceView,
    @NonNull GLRenderer.RenderCallback renderer
)

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
@NonNull SurfaceView surfaceView

SurfaceView that provides the surface to be rendered by the backing thread

@NonNull GLRenderer.RenderCallback renderer

callbacks used to create a corresponding EGLSurface from the given surface as well as render content into the created EGLSurface

Returns
@NonNull GLRenderer.RenderTarget

RenderTarget used for subsequent requests to communicate with the provided Surface (ex. requestRender or detach).

Throws
kotlin.IllegalStateException

If this method was called when the GLThread has not started (i.e. start has not been called)

attach

Added in 1.0.2
public final @NonNull GLRenderer.RenderTarget attach(
    @NonNull TextureView textureView,
    @NonNull GLRenderer.RenderCallback renderer
)

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
@NonNull TextureView textureView

TextureView that provides the surface to be rendered into on the GLThread

@NonNull GLRenderer.RenderCallback renderer

callbacks used to create a corresponding EGLSurface from the given surface as well as render content into the created EGLSurface

Returns
@NonNull GLRenderer.RenderTarget

RenderTarget used for subsequent requests to communicate with the provided Surface (ex. requestRender or detach).

Throws
kotlin.IllegalStateException

If this method was called when the GLThread has not started (i.e. start has not been called)

attach

Added in 1.0.2
public final @NonNull GLRenderer.RenderTarget attach(
    @NonNull Surface surface,
    int width,
    int height,
    @NonNull GLRenderer.RenderCallback renderer
)

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
@NonNull Surface surface

Target surface to be managed by the backing thread

int width

Desired width of the surface

int height

Desired height of the surface

@NonNull GLRenderer.RenderCallback renderer

Callbacks used to create a corresponding EGLSurface from the given surface as well as render content into the created EGLSurface

Returns
@NonNull GLRenderer.RenderTarget

RenderTarget used for subsequent requests to communicate with the provided Surface (ex. requestRender or detach).

Throws
kotlin.IllegalStateException

If this method was called when the GLThread has not started (i.e. start has not been called)

createRenderTarget

Added in 1.0.2
public final @NonNull GLRenderer.RenderTarget createRenderTarget(
    int width,
    int height,
    @NonNull GLRenderer.RenderCallback renderer
)

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
int width

Desired width of the RenderTarget

int height

Desired height of the RenderTarget

@NonNull GLRenderer.RenderCallback renderer

Callbacks used to issue OpenGL commands to the RenderTarget

Returns
@NonNull GLRenderer.RenderTarget

RenderTarget used for subsequent requests to render through RenderTarget.requestRender or to remove itself from the GLRenderer through RenderTarget.detach

Throws
kotlin.IllegalStateException

If this method was called when the GLThread has not started (i.e. start has not been called)

detach

Added in 1.0.2
public final void detach(
    @NonNull GLRenderer.RenderTarget target,
    boolean cancelPending,
    @WorkerThread Function1<@NonNull GLRenderer.RenderTargetUnit> onDetachComplete
)

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

Added in 1.0.2
public final void execute(@NonNull Runnable runnable)

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
@NonNull Runnable runnable

Runnable to be executed

isRunning

Added in 1.0.2
public final boolean isRunning()

Determines if the GLThread has been started. That is start has been invoked on this GLRenderer instance without a corresponding call to stop.

registerEGLContextCallback

Added in 1.0.2
public final void registerEGLContextCallback(
    @NonNull GLRenderer.EGLContextCallback callback
)

Add an EGLContextCallback to receive callbacks for construction and destruction of EGL dependencies.

These callbacks are invoked on the backing thread.

requestRender

Added in 1.0.2
public final void requestRender(
    @NonNull GLRenderer.RenderTarget target,
    Function1<@NonNull GLRenderer.RenderTargetUnit> onRenderComplete
)

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
@NonNull GLRenderer.RenderTarget target

RenderTarget to be re-rendered

Function1<@NonNull GLRenderer.RenderTargetUnit> onRenderComplete

Optional callback invoked on the backing thread after the frame has been rendered.

resize

Added in 1.0.2
public final void resize(
    @NonNull GLRenderer.RenderTarget target,
    int width,
    int height,
    Function1<@NonNull GLRenderer.RenderTargetUnit> onResizeComplete
)

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
@NonNull GLRenderer.RenderTarget target

RenderTarget to be resized

int width

Updated width of the corresponding surface

int height

Updated height of the corresponding surface

Function1<@NonNull GLRenderer.RenderTargetUnit> onResizeComplete

Optional callback invoked on the backing thread when the resize operation is complete

start

Added in 1.0.2
public final void start(@NonNull String name)

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
@NonNull String name

Optional name to provide to the GLThread

Throws
kotlin.IllegalStateException

if EGLConfig with desired attributes cannot be created

stop

Added in 1.0.2
public final void stop(boolean cancelPending, Function1<@NonNull GLRendererUnit> onStop)

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
boolean cancelPending

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.

Function1<@NonNull GLRendererUnit> onStop

Optional callback invoked on the backing thread after it is torn down.

unregisterEGLContextCallback

Added in 1.0.2
public final void unregisterEGLContextCallback(
    @NonNull GLRenderer.EGLContextCallback callback
)

Remove EGLContextCallback to no longer receive callbacks for construction and destruction of EGL dependencies.

These callbacks are invoked on the backing thread