This topic provides information about the points that the EGL specification explicitly states are platform-specific. This information is aimed at both users and implementers of EGL on the Symbian platform.
Applications can find out whether ScreenPlay (also known as the New Graphics Architecture or NGA) is supported on the device at runtime.
To do this, call eglQueryString(display,
EGL_EXTENSIONS)
and search for the string EGL_SYMBIAN_COMPOSITION
within the string returned. If EGL_SYMBIAN_COMPOSITION
is present, it means that ScreenPlay is supported. For further information,
see EGL Functions
with Symbian-Specific Behavior.
By checking for the presence
of the EGL_SYMBIAN_COMPOSITION
string, you can create
applications that can work on both ScreenPlay devices and those with
the non-ScreenPlay architecture.
EGL window surfaces are on-screen rendering surfaces
that are tied to Symbian windows. The RWindow
class
is a client-side handle to a Symbian Window Server window. You must
create the RWindow
before creating the EGL window
surface for on-screen rendering.
Because the EGL window surface is implemented differently depending on whether ScreenPlay is in use, there are some differences in how you create an EGL window surface:
In ScreenPlay, the pixel format of the EGL window surface is
determined entirely by the EGL config passed to eglCreateWindowSurface()
and not by the properties of the RWindow
.
On a non-ScreenPlay device, the display mode of the RWindow
must match the buffer size of the EGL window surface.
You can call RWindowBase::DisplayMode() const
to
retrieve the window’s display mode and use it to determine the buffer
size when retrieving the EGL config to pass to eglCreateWindowSurface()
.
Threading. Because of the limitations of the Window
Server API, clients must create and use an EGL window surface
in the thread in which its RWindow
was created. This
means that the following are not supported and will lead to
undefined behavior:
Creating an EGL window surface in thread B using an RWindow
that was created in thread A.
Using an EGL window surface in thread B when that EGL
window surface and its RWindow
were created in thread A.
For example, in the second scenario, EGL in thread B will fail (with a WSERV panic) when it attempts to get the window
size from the RWindow
in thread A.
Buffer handling. By default EGL window surfaces have multiple
buffers, which means that the client can draw to a back buffer, while
the front buffer is being composed to the screen. The client must
call eglSwapBuffers()
to post the back buffer to
the screen.
EGL 1.4 introduces a preserve buffer feature, which enables the content of the front buffer to be preserved from one frame to the next. This means that the client can provide incremental drawing operations rather than the entire drawing operations for each frame. This feature is usually off by default. This means that legacy applications that do not expect this feature are not slowed down by the unnecessary copying of the buffer contents.
Window resizing. The
size of an application’s view can be changed by a variety of external
events, such as a UI layout switch, a change in the size of the status
pane or the rotation of the screen. An application can also resize
a window directly, such as through a call to RWindow::SetExtent()
, CCoeControl::SetExtent()
or CCoeControl::SetExtentToWholeScreen()
.
When there is a change in the size of a window that is bound
to an EGL window surface, the application must take appropriate action
in its CCoeControl::SizeChanged(
) or CCoeControl::HandleResourceChange()
implementation. The action depends on the nature of the application
but might include clipping or scaling the contents to fit the resized
window.
On the Symbian platform, EGL handles the window resize
in the next call to eglSwapBuffers()
, which resizes
the surface to match the new window size. If the preserve buffer option
is in use, this function also copies across all the pixels from the
old surface that overlap the new surface, although the exact details
depend on the implementation.
If the surface resize fails, eglSwapBuffers()
returns EGL_FALSE
and
an EGL_BAD_ALLOC
error is raised. This may mean that
the implementation does not support the resizing of a surface or that
there is not enough memory available (on a platform with GPU, this
would be GPU rather than system memory). Applications must always
monitor whether eglSwapBuffers() fails after a
window resize. When it does fail, the application should do the following:
Call eglDestroySurface()
to destroy the current EGL window surface.
Call eglCreateWindowSurface()
to recreate the EGL window surface.
This may cause a noticeable flicker and so should be done only when necessary.
Screen rotation. There is no specific
EGL handling for screen rotation—instead screen rotation is handled
in the same way as a change of screen resolution. An application typically
handles changes in screen resolution and rotation in its CCoeAppUi::HandleScreenDeviceChangedL()
or CCoeControl::HandleResourceChange(TInt)
implementation. When there is a change in screen rotation, the application
may need to resize its windows and update the content accordingly.
In response to the application resizing its windows, the EGL
implementation updates the surface size on the next call to eglSwapBuffers()
. However, the interim frames appear in
the new orientation, and so an application may want to adjust the
contents to minimize flicker. If the application wants to accept the
system rotation, it does not need to rotate its content. However,
some applications may require a fixed physical orientation. These
need to rotate the window content in order to counteract the physical
rotation.
Sometimes a screen rotation simply results in the swapping of the window’s width and height dimensions—for example, when the application is running in full screen mode and the device is rotated from portrait to landscape or vice versa. This is guaranteed to succeed on all Symbian EGL implementations.
In other situations
the screen rotation must be treated like a window resize and the application
must monitor whether eglSwapBuffers()
succeeds and
take appropriate action if it fails, as described above. For example,
if the application is not in full screen mode, rotating the device
from portrait to landscape may not result in the swapping of the width
and height of the window.
ScreenChangeEvents
by calling RWindowGroup::EnableScreenChangeEvents()
. When an event
occurs, the application needs to take the steps listed below. Some
application frameworks may already implement some of these steps.Set the orientation
of the CWsScreenDevice
to the new orientation of
the device.
Resize the RWindow
. Do not allow any calls to eglSwapBuffers()
or eglCreateWindowSurface()
before you have resized
the window.
Tear down the
old eglWindowSurface
and create a new one in the
new orientation. This step may be carried out automatically by some
EGL implementations
void CExampleApp::HandleScreenDeviceChanged() { // Ask the window server what the current (new) screen mode is. const TInt screenMode = Screen()->CurrentScreenMode(); // Ask for the orientation and size of this new screen mode. TPixelsAndRotation pixelsAndRotation; Screen()->GetScreenModeSizeAndRotation(screenMode, pixelsAndRotation); const TSize screenSize = pixelsAndRotation.iPixelSize; const CFbsBitGc::TGraphicsOrientation rotation = pixelsAndRotation.iRotation; // Change the application's screen device to match the new // orientation and new size. Screen()->SetScreenSizeAndRotation(pixelsAndRotation); // Resize the window to full screen for the new orientation. iWindow0->SetSize(screenSize); // After resizing the window, it is safe to call eglSwapBuffers() // and eglCreateWindowSurface(). if (screenSize.iWidth > screenSize.iHeight) { iVgRenderer0->SetOrientationLandscape(); } else { iVgRenderer0->SetOrientationPortrait(); } }UI content. Applications that want to make use of the ScreenPlay ability to place semi-transparent
CWindowGc
rendering above the EGL window surface should check whether ScreenPlay
is supported on the device as described above. On ScreenPlay
devices, you can combine CWindowGc
drawing and
OpenVG/OpenGL ES drawing in the same window, provided the CWindowGc
content is drawn using a semi-transparent pen
or brush color or bitmap. It is also possible to create semi-transparent CWindowGc
drawing in another Symbian window placed over
the EGL window. To do this, make the Symbian window semi-transparent
by calling RWindow::SetTransparencyAlphaChannel()
. Transparent
Windows has more detail on implementing semi-transparent windows.
On non-ScreenPlay devices, you need to place the CWindowGc
drawing in an opaque child window over the EGL window surface or
implement the UI by using OpenVG/OpenGL ES drawing that is directed
to the EGL window surface itself.
Window lifetime. Clients
must maintain the RWindow
associated with the EGL
window surface for the lifetime of that window surface, provided they
follow the good practice guidelines of unbinding the EGL window surface
from the current context before destroying it. If these guidelines
are not followed, it may be necessary to maintain the RWindow
for the entire duration of EGL usage within the client application.
For example, the following pseudocode demonstrates good practice.
The RWindow
must be valid until eglDestroySurface()
is called:
// Unbind the window surface from the current context. eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); // Destroy the window surface. eglDestroySurface(display, surface); ... eglTerminate(display)
When the application does not
follow this good practice and destroys the surface before unbinding
it from the current context, the RWindow
must be
valid for longer. For example in the following pseudocode, RWindow
must be valid until after eglMakeCurrent()
is called:
eglDestroySurface(display, surface); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); ... eglTerminate(display)
If eglMakeCurrent() is not called with a null surface and null context at all, the RWindow
must be valid until eglTerminate()
is called.
Underlay/overlay. On Symbian, the concept
of enumerated overlay/underlay planes distinct from the Window Server’s
placement of layers does not exist. Windows are always positioned
first of all by their position in the window tree, while surfaces
are positioned to appear behind any CWindowGc
drawing
for their window, and it is not possible to have more than one surface
per window. Consequently, when choosing a config for a window surface,
the use of an EGL_LEVEL
other than 0 will inevitably
result in no matches found.
Native and non-native window orientation. The native orientation of a device is determined by the display panel. This piece of hardware defines both which part of the display is treated as the top and the direction in which pixels are scanned. The native orientation of a device does not change.
Figure: Pixel scanning in left to right direction from the display panel origin
Rendering in native orientation. Application content is rendered to the display panel in several stages. The following diagram summarizes the rendering pipeline. For simplicity, the compositor is shown as a single stage. The compositor back-end in the hardware adaptation layer and the compositor hardware are not shown.
Figure: Rendering pipeline showing application windows in native orientation
In the diagram the orientation of the display panel is
the same as the orientation of the application RWindow
and the associated window surface, which is an eglWindowSurface
. This indicates that the application windows are in native orientation.
Rendering in non-native orientation. When the physical
orientation of the device changes, this causes the compositor to present
a different orientation to the higher levels. The CWsScreenDevice
class is used to query the orientation as presented by the compositor.
When the compositor presents a non-native orientation, applications
create an RWindow
and an eglWindowSurface
that are also in the non-native orientation. This is illustrated
in the following diagram.
Figure: Compositor and application windows in non-native orientation
For some devices, this scenario causes a rotation cost in the compositor that can result in a reduced frame rate, and possibly an increase in graphics memory usage. An optimization is available to avoid the rotation cost. It is only relevant to Symbian^3 applications that create non-native orientation windows on device hardware that suffers from expensive compositor rotation. For an introduction to this optimization, see Optimizing Non-Native Orientation Windows in Symbian^3.
An EGL implementation can support the CFbsBitmap
pointer as an EGLNativePixmapType
. This means that it is possible to create an EGLSurface
to render to a CFbsBitmap
. However, it is not
guaranteed to be supported on all EGL implementations.
Most EGL calls include an EGLDisplay
parameter. The EGL specification describes this as "the abstract
display on which graphics are drawn". On some systems, this corresponds
to a physical screen. However, the details are platform specific and
on Symbian systems, it does not correspond to a physical screen.
When working on the Symbian platform, it is generally more useful
to think of an EGLDisplay
as the EGL session.
On Symbian systems, you usually use a single EGLDisplay
. You get this by a call to eglGetDisplay()
and
passing EGL_DEFAULT_DISPLAY
as the <display
id>
parameter.
The physical screen on which the content
is displayed is determined by the window's parent window group. In
Symbian, every window (RWindow
) has a parent window
group (RWindowGroup
), as shown in the following
diagram. When you create a window group, you can specify the screen
on which it is to be shown.
Figure: Each window has a parent window group which is associated with a screen
When you create a window surface in EGL using eglCreateWindowSurface
, you pass in the RWindow
as an argument. The window
surface is then displayed on the screen associated with that window's
parent window group. Currently a window can exist on only one screen.