×
Namespaces

Variants
Actions

Anti-tearing with CDirectScreenBitmap

From Nokia Developer Wiki
Jump to: navigation, search

This article discusses how CDirectScreenBitmap (also known as Anti-Tearing API) can be used to synchronize drawing to the LCD refresh rate and thereby avoid "tearing".

Article Metadata
Article
Created: gafgafgaf (04 May 2007)
Last edited: hamishwillee (14 Jun 2013)

Introduction

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, which is also know as the Anti-Tearing API (a brief description of CDirectScreenBitmap can be found in TSS000307 - Direct screen access with CDirectScreenBitmap). 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.

Warning.pngWarning: Some phones may not support this API

Sample code

This sample code contains a class (partially) that implements anti-tearing rendering.

Note.pngNote: 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();
}
This page was last modified on 14 June 2013, at 08:03.
62 page views in the last 30 days.
×