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.