This tutorial describes the high level steps that you need to take when writing applications using EGL to create a window surface for on-screen rendering. The code snippets use C style conventions. To avoid unnecessary complexity, they do not contain complete error handling.
This tutorial assumes a background knowledge of the following:
You must get and initialize
the EGLDisplay
prior to calling most other EGL or client
API functions. You only need to do this once.
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, NULL, NULL);
EGL has the concept
of current rendering API. To make one of the EGL client APIs the current
rendering API for the thread, call eglBindAPI()
passing EGL_OPENVG_API
or EGL_OPENGLES_API
as
required. For example:
// Set OpenGL ES as the current rendering API for the thread eglBindAPI(EGL_OPENGLES_API);
Use the eglChooseConfig() method to get the EGLConfig
that
matches a list of attributes. In order to render to an RWindow
,
these must include the EGL_WINDOW_BIT
.
// List of attributes to pass to eglChooseConfig. const EGLint KColorRGB565AttribList[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, EGL_NONE }; EGLint numConfigs; EGLConfig chosenConfig = 0; // Get the config to use. eglChooseConfig(display, KColorRGB565AttribList, &chosenConfig, 1, &numConfigs); if (numConfigs == 0) { RDebug::Printf("No matching configs found"); User::Leave(KErrNotSupported); }
Note: By default the EGL_SURFACE_TYPE
has
the EGL_SWAP_BEHAVIOR_PRESERVED_BIT
set for window surfaces
in order to support the preserve buffer option. You can set this explicitly
like this:
EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
To create an on-screen
rendering surface, you first need to create a Symbian Window Server window
(RWindow
). This window is then passed as the third argument
to eglCreateWindowSurface()
along with an EGLConfig
that
has the EGL_WINDOW_BIT
set.
// Create a window surface to draw to. winSurface = eglCreateWindowSurface(display, chosenConfig, &iWindow, NULL);
Set the surface attribute EGL_SWAP_BEHAVIOR
to EGL_BUFFER_PRESERVED
. This step is only required if you want to
enable the preserve buffer option.
EGLBoolean queryResult = eglSurfaceAttrib(display, winSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
To create a rendering
context for the current rendering API, call the eglCreateContext()
with
the share_context
parameter set to EGL_NO_CONTEXT
.
If this method succeeds, it initializes the context to the initial state defined
for the current rendering API, and returns a handle to it.
// Create a context to store the current rendering API settings. contextGL = eglCreateContext(display, chosenConfig, EGL_NO_CONTEXT, NULL);
In order to allow the
context to render to a given surface, you need to call eglMakeCurrent()
.
After doing this you can call EGL client functions, which need a current surface
and context.
// Make the context current on the surface and the display eglMakeCurrent(display, winSurface, winSurface, contextGL);
You are now ready to perform your OpenGL ES drawing commands.
The main thing to understand
is that the EGL window surface is double-buffered. This means that the drawing
commands are drawn into a back buffer and you need to call eglSwapBuffers()
in
order to make the drawing appear on the screen in the window. This mechanism
has the advantage that it stops flicker.
eglSwapBuffers(display, winSurface);
Because you enabled the preserve buffer option in step 5, the eglSwapBuffers()
promotes
the back buffer to the front for display as usual, and also copies the content
to the new back buffer. This means the client application can provide incremental
drawing commands instead of creating the entire new scene.
To release the current
context and surface without assigning a new one, set the context parameter
to EGL_NO_CONTEXT
and set the draw and read surfaces to EGL_NO_SURFACE
.
This flushes the current context for the current rendering API and marks it
as no longer current. The current rendering API does not have a current context
after eglMakeCurrent()
returns.
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
You destroy the rendering
context by calling eglDestroyContext()
. All resources associated
with the context are marked for deletion as soon as possible. If the context
is current to any thread, resources are not actually released while the context
remains current.
eglDestroyContext(display, contextGL);
You destroy the EGLSurface
by
calling eglDestroySurface()
. All resources associated with
the surface are marked for deletion as soon as possible. If the surface is
current to any thread, the resources are not actually released while the surface
remains current.
eglDestroySurface(display, winSurface);
Perform final cleanup
by first terminating the EGLDisplay
using eglTerminate()
and
then releasing any resources still held by EGL by calling eglReleaseThread()
.
eglTerminate(display); eglReleaseThread();