Symbian-Specific Behavior

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.

ScreenPlay (NGA)

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.

Symbian windows

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:

  1. Call eglDestroySurface() to destroy the current EGL window surface.

  2. 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.

Example of a full-screen orientation switch. An application wishing to handle an orientation switch must first subscribe to 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.
  1. Set the orientation of the CWsScreenDevice to the new orientation of the device.

  2. Resize the RWindow. Do not allow any calls to eglSwapBuffers() or eglCreateWindowSurface() before you have resized the window.

  3. 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

The following code example illustrates these steps:
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.

The following diagram shows a display panel with a portrait native orientation which scans pixels left to right as indicated by the arrows. Note that the choice of portrait as the native device orientation is for illustration only.

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.

Symbian pixmap types

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.

Display handling

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.

Related concepts