Renderer.GlesRenderer

public abstract class Renderer.GlesRenderer extends Renderer

Object
   ↳ Renderer
     ↳ Renderer.GlesRenderer

Watch faces that require GLES20 rendering should extend their Renderer from this class.

A GlesRenderer is expected to be constructed on the background thread associated with WatchFaceService.getBackgroundThreadHandler inside a call to WatchFaceService.createWatchFace. All rendering is be done on the UiThread. There is a memory barrier between construction and rendering so no special threading primitives are required.

Two linked EGLContexts are created eglBackgroundThreadContext and eglUiThreadContext which are associated with background and UiThread respectively. OpenGL objects created on (e.g. shaders and textures) can be used on the other.

If you need to make any OpenGl calls outside of render, onBackgroundThreadGlContextCreated or onUiThreadGlSurfaceCreated then you must use either runUiThreadGlCommands or runBackgroundThreadGlCommands to execute a Runnable inside of the corresponding context. Access to the GL contexts this way is necessary because GL contexts are not shared between renderers and there can be multiple watch face instances existing concurrently (e.g. headless and interactive, potentially from different watch faces if an APK contains more than one WatchFaceService). In addition most drivers do not support concurrent access.

Throws
androidx.wear.watchface.Renderer.GlesRenderer.GlesException

If any GL calls fail during initialization.

Summary

Nested types

Renderer.GlesRenderer.GlesException

Exception thrown if a GL call fails

Public fields

final @NonNull Collection<@NonNull Pair<@NonNull Integer, @NonNull ContentDescriptionLabel>>

Accessibility ContentDescriptionLabel for any rendered watch face elements other than the time and ComplicationSlots which are generated automatically.

final @Px float

The center x coordinate of the SurfaceHolder this Renderer renders into.

final @Px float

The center y coordinate of the SurfaceHolder this Renderer renders into.

lateinit final @NonNull EGLContext

The GlesRenderer's background Thread EGLContext.

final @NonNull EGLConfig

The GlesRenderer's EGLConfig.

final @NonNull EGLDisplay

The GlesRenderer's EGLDisplay.

lateinit final @NonNull EGLContext

The GlesRenderer's UiThread EGLContext.

final long

The interval in milliseconds between frames in interactive DrawModes.

final @NonNull RenderParameters

The current RenderParameters.

final @NonNull Rect

The bounds of the SurfaceHolder this Renderer renders into.

final @NonNull SurfaceHolder

The SurfaceHolder that renderInternal will draw into.

Public constructors

GlesRenderer(
    @NonNull SurfaceHolder surfaceHolder,
    @NonNull CurrentUserStyleRepository currentUserStyleRepository,
    @NonNull WatchState watchState,
    @IntRange(from = 0, to = 60000) long interactiveDrawModeUpdateDelayMillis,
    @NonNull int[] eglConfigAttribList,
    @NonNull int[] eglSurfaceAttribList
)

Public methods

@WorkerThread void

Called once a background thread when a new GL context is created on the background thread, before any subsequent calls to render.

@CallSuper void

Called when the Renderer is destroyed.

@UiThread void
onUiThreadGlSurfaceCreated(@Px int width, @Px int height)

Called once when a new GL surface is created on the UiThread, before any subsequent calls to render.

abstract @UiThread void
render(@NonNull ZonedDateTime zonedDateTime)

Sub-classes should override this to implement their watch face rendering logic which should respect the current renderParameters.

abstract @UiThread void

Sub-classes should override this to implement their watch face highlight layer rendering logic for the RenderParameters.highlightLayer aspect of renderParameters.

final @WorkerThread void

Inside of a synchronized block this function sets the GL context associated with the WatchFaceService.getBackgroundThreadHandler's looper thread as the current one, executes runnable and finally unsets the GL context.

final @UiThread void

Inside of a synchronized block this function sets the UiThread GL context as the current one, executes runnable and finally unsets the GL context.

Inherited methods

From class Renderer
@UiThread @NonNull Rect

This method is used for accessibility support to describe the portion of the screen containing the main clock element.

final @UiThread void

Schedules a call to either CanvasRenderer.render or GlesRenderer.render to draw the next frame.

final void

Posts a message to schedule a call to either CanvasRenderer.render or GlesRenderer.render to draw the next frame.

@UiThread boolean

The system periodically (at least once per minute) calls onTimeTick() to trigger a display update.

Public fields

additionalContentDescriptionLabels

@NonNull
public final @NonNull Collection<@NonNull Pair<@NonNull Integer, @NonNull ContentDescriptionLabel>> additionalContentDescriptionLabels

Accessibility ContentDescriptionLabel for any rendered watch face elements other than the time and ComplicationSlots which are generated automatically.

The Int in the Pair<Int, ContentDescriptionLabel> is used to sort the ContentDescriptionLabels. Note the time piece has an accessibility traversal index of -1 and each ComplicationSlot's index is defined by its ComplicationSlot.accessibilityTraversalIndex.

centerX

@Px
@NonNull
public final @Px float centerX

The center x coordinate of the SurfaceHolder this Renderer renders into.

centerY

@Px
@NonNull
public final @Px float centerY

The center y coordinate of the SurfaceHolder this Renderer renders into.

eglBackgroundThreadContext

@NonNull
public lateinit final @NonNull EGLContext eglBackgroundThreadContext

The GlesRenderer's background Thread EGLContext.

eglConfig

@NonNull
public final @NonNull EGLConfig eglConfig

The GlesRenderer's EGLConfig.

eglDisplay

@NonNull
public final @NonNull EGLDisplay eglDisplay

The GlesRenderer's EGLDisplay.

eglUiThreadContext

@NonNull
public lateinit final @NonNull EGLContext eglUiThreadContext

The GlesRenderer's UiThread EGLContext. Note this not available until after WatchFaceService.createWatchFace has completed.

interactiveDrawModeUpdateDelayMillis

@NonNull
public final long interactiveDrawModeUpdateDelayMillis

The interval in milliseconds between frames in interactive DrawModes. To render at 60hz set to 16. Note when battery is low, the frame rate will be clamped to 10fps. Watch faces are recommended to use lower frame rates if possible for better battery life. Variable frame rates can also help preserve battery life, e.g. if a watch face has a short animation once per second it can adjust the frame rate inorder to sleep when not animating.

renderParameters

@NonNull
public final @NonNull RenderParameters renderParameters

The current RenderParameters. Updated before every onDraw call.

screenBounds

@NonNull
public final @NonNull Rect screenBounds

The bounds of the SurfaceHolder this Renderer renders into. Depending on the shape of the device's screen not all of these pixels may be visible to the user (see Configuration.isScreenRound). Note also that API level 27+ devices draw indicators in the top and bottom 24dp of the screen, avoid rendering anything important there.

surfaceHolder

@NonNull
public final @NonNull SurfaceHolder surfaceHolder

The SurfaceHolder that renderInternal will draw into.

Public constructors

GlesRenderer

@WorkerThread
public final GlesRenderer(
    @NonNull SurfaceHolder surfaceHolder,
    @NonNull CurrentUserStyleRepository currentUserStyleRepository,
    @NonNull WatchState watchState,
    @IntRange(from = 0, to = 60000) long interactiveDrawModeUpdateDelayMillis,
    @NonNull int[] eglConfigAttribList,
    @NonNull int[] eglSurfaceAttribList
)
Parameters
@NonNull SurfaceHolder surfaceHolder

The SurfaceHolder whose android.view.Surface will draw into.

@NonNull CurrentUserStyleRepository currentUserStyleRepository

The associated CurrentUserStyleRepository.

@NonNull WatchState watchState

The associated WatchState.

@IntRange(from = 0, to = 60000) long interactiveDrawModeUpdateDelayMillis

The interval in milliseconds between frames in interactive DrawModes. To render at 60hz set to 16. Note when battery is low, the frame rate will be clamped to 10fps. Watch faces are recommended to use lower frame rates if possible for better battery life. Variable frame rates can also help preserve battery life, e.g. if a watch face has a short animation once per second it can adjust the frame rate inorder to sleep when not animating.

@NonNull int[] eglConfigAttribList

Attributes for EGL14.eglChooseConfig. By default this selects an RGBA8888 back buffer.

@NonNull int[] eglSurfaceAttribList

The attributes to be passed to EGL14.eglCreateWindowSurface. By default this is empty.

Public methods

onBackgroundThreadGlContextCreated

@WorkerThread
@NonNull
public @WorkerThread void onBackgroundThreadGlContextCreated()

Called once a background thread when a new GL context is created on the background thread, before any subsequent calls to render. Note this function is called inside a lambda passed to runBackgroundThreadGlCommands which has synchronized access to the GL context.

onDestroy

@CallSuper
@NonNull
public @CallSuper void onDestroy()

Called when the Renderer is destroyed.

onUiThreadGlSurfaceCreated

@UiThread
@NonNull
public @UiThread void onUiThreadGlSurfaceCreated(@Px int width, @Px int height)

Called once when a new GL surface is created on the UiThread, before any subsequent calls to render. Note this function is called inside a lambda passed to runUiThreadGlCommands which has synchronized access to the GL context.

Parameters
@Px int width

width of surface in pixels

@Px int height

height of surface in pixels

render

@UiThread
@NonNull
public abstract @UiThread void render(@NonNull ZonedDateTime zonedDateTime)

Sub-classes should override this to implement their watch face rendering logic which should respect the current renderParameters. Any highlights due to RenderParameters.highlightLayer should be rendered by renderHighlightLayer instead where possible. For correct behavior this function must use the supplied ZonedDateTime in favor of any other ways of getting the time.

Note this function is called inside a lambda passed to runUiThreadGlCommands which has synchronized access to the GL context.

Note also GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ZERO) is called by the library before this method.

Before any calls to this function onBackgroundThreadGlContextCreated and onUiThreadGlSurfaceCreated will have been called once on their respective threads.

Parameters
@NonNull ZonedDateTime zonedDateTime

The zonedDateTime ZonedDateTime to render with

renderHighlightLayer

@UiThread
@NonNull
public abstract @UiThread void renderHighlightLayer(@NonNull ZonedDateTime zonedDateTime)

Sub-classes should override this to implement their watch face highlight layer rendering logic for the RenderParameters.highlightLayer aspect of renderParameters. Typically the implementation will clear the buffer to RenderParameters.HighlightLayer.backgroundTint before rendering a transparent highlight or a solid outline around the RenderParameters.HighlightLayer.highlightedElement. This will be composited as needed on top of the results of render. For correct behavior this function must use the supplied ZonedDateTime in favor of any other ways of getting the time.

Note this function is called inside a lambda passed to runUiThreadGlCommands which has synchronized access to the GL context.

Note also GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ZERO) is called by the library before this method.

Parameters
@NonNull ZonedDateTime zonedDateTime

The zonedDateTime ZonedDateTime to render with

runBackgroundThreadGlCommands

@WorkerThread
@NonNull
public final @WorkerThread void runBackgroundThreadGlCommands(@NonNull Runnable runnable)

Inside of a synchronized block this function sets the GL context associated with the WatchFaceService.getBackgroundThreadHandler's looper thread as the current one, executes runnable and finally unsets the GL context.

Access to the GL context this way is necessary because GL contexts are not shared between renderers and there can be multiple watch face instances existing concurrently (e.g. headless and interactive, potentially from different watch faces if an APK contains more than one WatchFaceService).

NB this function is called by the library before running runBackgroundThreadGlCommands so there's no need to use this directly in client code unless you need to make GL calls outside of those methods.

Throws
kotlin.IllegalStateException

if the calls to EGL14.eglMakeCurrent fails

runUiThreadGlCommands

@UiThread
@NonNull
public final @UiThread void runUiThreadGlCommands(@NonNull Runnable runnable)

Inside of a synchronized block this function sets the UiThread GL context as the current one, executes runnable and finally unsets the GL context.

Access to the GL context this way is necessary because GL contexts are not shared between renderers and there can be multiple watch face instances existing concurrently (e.g. headless and interactive, potentially from different watch faces if an APK contains more than one WatchFaceService).

NB this function is called by the library before running render or