This topic describes a hardware-dependent performance optimization that is relevant for application developers working on Symbian Platfrom devices on which rotation at the compositor level is expensive. The optimization is not relevant for device hardware that does not suffer from the cost of compositor level rotation.
This topic follows on from the introduction to native and non-native window orientation in Symbian-Specific Behavior.
Note. For the sake of clarity this topic assumes the device
display panel has a native orientation of portrait. Therefore a landscape RWindow
and eglWindowSurface
are considered
to be in non-native orientation. See Modifications for Khronos rendering: handling different screen sizes
and rotation at the end of the topic for further information.Which applications will benefit from the optimization?
The potential candidates for using FixNativeOrientation
windows are application developers who wish to use a full-screen eglWindowSurface
in landscape orientation. A typical use
case is a game that can only operate in landscape. For some devices
this scenario causes a rotation cost in the compositor, resulting
in a reduced frame rate and possibly an increase in graphics memory
usage.
If you are working on such a device and you have a use case where
you wish to avoid the performance overhead and maintain as fast a
frame rate as possible then you can use the FixNativeOrientation()
function described in this topic.
The effect of the optimization
When an application creates an RWindow
in landscape
orientation, by default the associated eglWindowSurface
is also in landscape. In this situation the orientation of the eglWindowSurface
is not the same as the native orientation
of the display panel. As a result the compositor may suffer a rotation
cost when rendering output to the display panel.
Calling FixNativeOrientation()
when you create
the RWindow
addresses this problem by allowing the
application to use a landscape RWindow
along with
a portrait eglWindowSurface
. The eglWindowSurface
remains in the same orientation as the display panel and the expensive
compositor rotation is avoided.
The diagram shows the result of a successful call to FixNativeOrientation()
.
Figure: Effect of calling FixNativeOrientation()
eglWindowSurface
changes as a result of the call. The compositor still presents a
landscape orientation and there is no difference in the way the Window
Server interacts with the landscape RWindow
. The
abstract view of the application content also remains in landscape
orientation and pointer events are sent to the application accordingly.As a result of calling FixNativeOrientation()
it
is necessary for the application to carry out geometric operations
to compensate for the mismatch between the orientation of the application
content and the orientation of the eglWindowSurface
. Geometric rotation and translation are required when carrying out
OpenVG or OpenGL ES rendering from the application to the eglWindowSurface
. The calculations will vary depending on
which of the Khronos APIs are used. On devices where this optimization
is required, the cost of these geometric operations is very small
in comparison to the cost of rotation by the compositor that has been
avoided.
When to use a FixNativeOrientation() window
You are writing a client application using a full-screen eglWindowSurface
in non-native orientation (assumed to be
landscape in this topic). The window will be positioned at the origin
and never resized.
The device hardware suffers from expensive compositor rotation and the performance requirements of your application mean you need to avoid this cost.
How to setup the RWindow
Have a CWsScreenDevice
active and set up in the landscape orientation.
Create an RWindow
with a landscape, full screen, origin based, window.
Immediately
call RWindow::FixNativeOrientation()
to activate
the orientation independent behaviour.
Activate the window .
Create an eglWindowSurface
with the window.
Handling FixNativeOrientation() error codes
It is important to check the error return code from FixNativeOrientation()
. Only proceed to use the window if the return code is KErrNone
.
If the function returns KErrNotSupported
, the
feature is not supported. As the optimization is not available, you
should close the window and create your window again as normal without
calling FixNativeOrientation()
.
In the case of any other return code such as KErrNoMemory
, you should abort window creation. Typically your context would
be the ConstructL()
of a CCoeControl
, so you would call User::Leave(KErrNoMemory)
.
Effect of FixNativeOrientation() on pointer event handling
For an application that you have written to run in landscape (i.e.
non-native) orientation no new actions are required to handle pointer
events as a result of calling RWindow::FixNativeOrientation()
. Pointer events are sent to the application as before, in the landscape
orientation.
When the device is in landscape, the application uses a CWsScreenDevice
to find out from the Window Server that
the screen has a landscape aspect ratio. Normally, an application
wishing to create a full screen window would create a window with
a landscape aspect ratio. Assuming a landscape screen size of 640
x 360 the size of the window would be defined by TRect(0,0,640,360)
. This stays the same for FixNativeOrientation
windows.
Modifications required for Khronos rendering
Creating an eglWindowSurface
on a landscape full-screen FixNativeOrientation
window results in a portrait sized
surface. Assuming a screen size of 640 x 360 the RWindow
has extent TRect(0,0,640,360)
and the eglWindowSurface
has size 360, 640.
Khronos rendering into the surface using OpenVG or OpenGL ES will reach the screen in a native orientation (portrait). As a result a translate and counter-rotation is required to put non-native (landscape) rendering into the native (portrait) surface.
Here is an example for OpenVG rendering:
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); vgLoadIdentity(); if (iFixNativeOrientationEnabled && iLandscapeRendering) { vgRotate(-90.0f); vgTranslate(0.0f, -640.0f); }
See Modifications for Khronos rendering: handling different screen sizes and rotation for a more flexible example.
Constraints on the use of FixNativeOrientation() windows
The RWindow
on which you call FixNativeOrientation()
must be full-screen. For a screen size of 640 x 360 the window
must be 640 x 360.
The RWindow
must be positioned at the origin. The position of
the window must be at (0,0) in screen co-ordinates. Non-origin position
windows are not supported.
Resizing of
the eglWindowSurface
is not supported. FixNativeOrientation()
does not allow an eglWindowSurface
to be resized
after it has been created.
Call FixNativeOrientation()
immediately after setting the extent
of the RWindow
and before activating it.
Ensure the application's CWsScreenDevice
is not destroyed during the lifetime of
the RWindow
on which you call FixNativeOrientation()
. The client will be panicked by the Window Server if this constraint
is violated.
On some devices,
the optimization benefits of FixNativeOrientation()
are not achieved if an external display is plugged in to the device.
FixNativeOrientation()
returns KErrNotSupported
in an emulator environment.
The following code example illustrates the steps involved in creating
a FixNativeOrientation()
window. The example assumes
the native orientation of the display panel is portrait.
void CExampleApp::ConstructL() { RWsSession wsSession; User::LeaveIfError(wsSession.Connect()); RGroupWindow groupWin = RWindowGroup(wsSession); User::LeaveIfError(groupWin.Construct(0x111, ETrue)); groupWin.EnableScreenChangeEvents(); // You must have a valid screen device before calling // FixNativeOrientation(). CWsScreenDevice* scrdev = new(ELeave) CWsScreenDevice(wsSession); User::LeaveIfError(scrdev->Construct(0)); // If the device is in landscape, the application's screen device // should be in landscape too. const TSize screenSize = scrdev->SizeInPixels(); // Attempt to create the RWindow with FixNativeOrientation enabled. TRAPD(err, ConstructWindowL(ETrue)); switch (err) { case KErrNone: break; case KErrNotSupported: // The feature is not supported, so delete and recreate // the window without using FixNativeOrientation(). delete iWindow; iWindow = NULL; ConstructWindowL(EFalse); break; default: User::Leave(err); } // Create an eglWindowSurface with the window. InitEgl(); } void CExampleApp::ConstructWindowL(TBool aFixNativeOrientation) { iWindow = new (ELeave) RWindow(wsSession); RWindow& window = *iWindow; window.Construct(iGroupWin1, 0x100); // Set the window to the current screen size. If the screen device // tells us we are in landscape, proceed to create a window with // landscape dimensions. window.SetExtent(TPoint(0, 0), screenSize); if (aFixNativeOrientation) { // Call RWindow::FixNativeOrientation() immediately after setting // the extent of the window. TInt err = window.FixNativeOrientation(); // Handle the error code returned by FixNativeOrientation. switch (err) { case KErrNone: iFixNativeOrientationEnabled = ETrue; break; case KErrNotSupported: default: iFixNativeOrientationEnabled = EFalse; User::Leave(err); } } // Activate the window. window.Activate(); wsSession.Flush(); }
Modifications for Khronos rendering: handling different screen sizes and rotations
The native orientation of all device display panels is portrait with dimensions of 360 x 640 pixels.
The only orientations available are 0 degrees and 90 degrees.
// An example that handles different screen dimensions and rotations. vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); vgLoadIdentity(); // When FixNativeOrientation() is used, the application is responsible for // rotating non-native rendering into surface. if (iFixNativeOrientationEnabled) { switch(iOrientation) { case CFbsBitGc::EGraphicsOrientationNormal: break; case CFbsBitGc::EGraphicsOrientationRotated90: vgTranslate(0.0f, surfaceHeight); vgRotate(-90.0f); break; case CFbsBitGc::EGraphicsOrientationRotated180: vgTranslate(surfaceWidth , surfaceHeight); vgRotate(180.0f); break; case CFbsBitGc::EGraphicsOrientationRotated270: vgTranslate(surfaceWidth, 0.0f); vgRotate(90.0f); break; } }
The following code shows how to obtain the size of the surface used in the transform above:
// Example of how to obtain surface dimensions for rotation transform. EGLint surfaceWidth = 0; EGLint surfaceHeight = 0; eglQuerySurface(iEglDisplay, iEglSurface, EGL_WIDTH, &surfaceWidth); eglQuerySurface(iEglDisplay, iEglSurface, EGL_HEIGHT, &surfaceHeight);
The rotation can be obtained from TPixelsAndRotation
as obtained from the screen device when handling the screen change
event:
void ExampleApp::HandleScreenDeviceChanged() { ... // 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; // Provide the vg renderer with current rotation. iVgRenderer->SetOrientation(rotation); ... }