You Are Here:

Community: Wiki

This page was last modified on 18 September 2009, at 20:21.

Anti-tearing with CDirectScreenBitmap

From Forum Nokia Wiki

Reviewer Approved   

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. If 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 Wiki Articles

No related wiki articles found

Rate This

 
Bookmark this page: DeliciousDiggFacebookGoogleYahooStumbleUponRedditDiigoTechnocratiTwitter  Share this page Share this page Print this Page Print this page Invite a friend Invite a friend
京ICP备05048969号    Email Newsletters Press Terms & Conditions Privacy Policy Sitemap Contact Us © 2009 Nokia