Categories: Symbian C++ | Code Examples | Imaging | Multimedia | Games
This page was last modified 07:34, 31 December 2007.
Anti-tearing with CDirectScreenBitmap
From Forum Nokia Wiki
When developing games with fast-paced graphics it is desirable to avoid using Windows server when drawing to screen. There are several options to access screen directly, see here.
This article focuses on using CDirectScreenBitmap class.
The Anti-Tearing API
With this API it is possible to synchronize drawing to the LCD refresh rate (which is typically between 60 and 75Hz).
More details about the phenomenon "tearing" can be read here.
Quick description of CDirectScreenBitmap (also called as Anti-Tearing API) can be found here
(Note that some phones may not support this API!)
Sample code
This sample code contains a class (partially) that implements anti-tearing rendering.
Important!
For performance reasons, the code does not wait video driver to complete drawing the frame to the LCD. Instead it lets the application deal with the next frame. It the frame rate of the game is too fast, it may happen that we start updating the screen buffer while the video driver is still busy with rendering the previous frame. (It may lead to flickering.) To avoid flickering, the game's frame rate should be maximized to the half of the LCD refresh rate (e.g. max. 30 frames / sec).
// ------------------------------------------- // header file // ------------------------------------------- ... #include <cdsb.h> //CDirectScreenBitmap link to scdv.lib #define TMpPixel TUint32 class CRendering : public CActive, public MDirectScreenAccess { // Construction, etc ... public: void ProcessFrame(); void BeginDraw(); void EndDraw(); public: // from MDirectScreenAccess virtual void Restart( RDirectScreenAccess::TTerminationReasons aReason ); virtual void AbortNow( RDirectScreenAccess::TTerminationReasons aReason ); protected: // from CActive void DoCancel(); void RunL(); private: CRendering(); void ConstructL( RWindow& aWindow ); private: CDirectScreenAccess* iDrawer; CDirectScreenBitmap* iDSBitmap; TMpPixel* iScreenAddress; }; ... // ------------------------------------------- // cpp file // ------------------------------------------- ... CRendering::~CRendering() { // "Cancel" is a meaningless call, since the service // (video driver's screen update process) is not cancellable. // When destroying this active object, you must make sure, // that the last update request (CDirectScreenBitmap::EndUpdate()) is completed. // Assuming that LCD refresh rate is not less than 60 Hz, // the wait time should be more than 1/60 secs. // (Otherwise a stay signal comes.) Cancel(); delete iDrawer; delete iDSBitmap; } CRendering::CRendering(): CActive( CActive::EPriorityStandard ) { } void CRendering::ConstructL( RWindow& aWindow ) { CActiveScheduler::Add( this ); // Setting up direct screen access iDSBitmap = CDirectScreenBitmap::NewL(); iDrawer = CDirectScreenAccess::NewL( CEikonEnv::Static()->WsSession(), *CEikonEnv::Static()->ScreenDevice(), aWindow, *this); CEikonEnv::Static()->WsSession().Flush(); iDrawer->StartL(); CFbsBitGc* gc = iDrawer->Gc(); RRegion* region = iDrawer->DrawingRegion(); gc->SetClippingRegion(region); // It may happen that a device does not support double buffering. User::LeaveIfError( iDSBitmap->Create( TRect(0, 0, KMpScreenWidth, KMpScreenHeight), CDirectScreenBitmap::EDoubleBuffer)); } void CRendering::Restart( RDirectScreenAccess::TTerminationReasons /*aReason*/ ) { TRAPD( err, iDrawer->StartL() ); // You may panic here, if you want CFbsBitGc* gc = iDrawer->Gc(); RRegion* region = iDrawer->DrawingRegion(); gc->SetClippingRegion(region); iDSBitmap->Create( TRect(0, 0, KMpScreenWidth, KMpScreenHeight), CDirectScreenBitmap::EDoubleBuffer); // Put some code here to continue game engine } void CRendering::AbortNow( RDirectScreenAccess::TTerminationReasons /*aReason*/ ) { // Put some code here to suspend game engine iDSBitmap->Close(); } void CRendering::RunL() { // Video driver finished to draw the last frame on the screen // You may initiate rendering the next frame from here, // but it would be slow, since there is a delay between CDirectScreenBitmap::EndUpdate() // and the completition of screen refresh by the video driver } void CRendering::DoCancel() { // Cancel not implemented in service provider, so we can't do anything here } void CRendering::BeginDraw() { // Obtain the screen address every time before drawing the frame, // since the address always changes TAcceleratedBitmapInfo bitmapInfo; iDSBitmap->BeginUpdate(bitmapInfo); iScreenAddress = (TMpPixel*)bitmapInfo.iAddress; } void CRendering::EndDraw() { if (IsActive()) { Cancel(); } iDSBitmap->EndUpdate(iStatus); SetActive(); // We don't need to wait to complete the request // We can start making the next frame instead. } void CRendering::ProcessFrame() { // This method is responsible to render and draw a frame to the screen BeginDraw(); // render the frame using iScreenAddress EndDraw(); }
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| MSCOMM commevent=3 | glenn_johnson | PC Suite API and PC Connectivity SDK | 1 | 2003-12-17 22:32 |
| How to - Dynamically update icons in List or Dialog | relliott98 | Symbian User Interface | 1 | 2005-06-13 14:08 |
| 6630 Hard reset without using *#7370# | brianpegan | General Discussion | 16 | 2008-07-04 03:18 |
| Nokia 6630 and Internet Connection through PC | jufaily | General Discussion | 1 | 2005-09-18 18:45 |
| N80 midlet icon problem revisited... questions | kounapuu | Mobile Java General | 1 | 2006-10-07 20:15 |
