При рисовании на экран с использованием сервера окна требуется переключить контекст, что замедляет рисование. Увеличить скорость рисования можно, отказавшись от использования сервера окна и получив прямой доступ к экрану. Эту технику будем называтьпрямым рисованием (Direct Draw).
Symbian OS позволяет реализовать прямое рисование тремя способами:
CFbsScreenDevice представляет собой графическое устройство, которое может посылать информацию драйверу экрана SCDV.DLL. После создания CFbsBitGc графического контекста, с ним можно работать как с любым графическим устройством. Однако, рисование происходит напрямую без использования сервера окна.
Самым быстрым способом рисования является прямой доступ к видеопамяти:
void CMyGameView::FillScreenDirectly()const { TPckgBuf<tscreeninfov01> infoPckg; TScreenInfoV01& screenInfo= infoPckg(); UserSvr::ScreenInfo(infoPckg); TUint16* screenMemory=(TUint16*) screenInfo.iScreenAddress+16; for(TInt y=0; y< screenInfo.iScreenSize.iHeight; y++) { for(TInt x=0; x< screenInfo.iScreenSize.iWidth; x++) { *screenMemory++=0; } } }</tscreeninfov01>
В памяти экрана расположен 32-байтный заголовок, который нужно принимать во внимание при работе.
Рисование в память напрямую происходит быстрее, чем через CFbsScreenDevice, но доступные программисту функциональные возможности зависят от модели устройства. Например, в одних телефонах содержание экрана обновляется автоматически при изменении памяти, в других - требуется принудительное обновление.
При использовании прямого доступа к памяти Вы не сможете запустить программу на эмуляторе. Тестирование необходимо проводить на целевом устройстве. Конечно, Вы можете решить эту проблему, используя вспомогательное изображение. При запуске на эмуляторе работайте с адресным пространством изображения, а при запуске на устройстве - с видеопамятью.
void CMyGameView::MyDrawing() { #ifdef __WINS__ // Работаем с рисунком TUint16* myScreenPointer= iMyBitmap.DataAddress(); #else // Аппаратная среда // Работаем с видеопамятью TUint16* myScreenPointer= GetMyScreenAddress(); #endif DoMyDrawing(myScreenPointer); }
Общей проблемой для методов прямого рисования является то, что сервер окна не знает о рисовании, поэтому он не может послать приложению уведомление о том, что оно потеряло фокус и другое окно выдвинуто на передний план. Не смотря на то, что приложение получит сообщение о потери фокуса, Вы не сможете достаточно быстро остановить прямое рисование, и экран окажется "загрязнен". Это может, например, произойти, если во время работы приложения получен входящий звонок, и приложение телефона выходит на передний план.
Symbian OS предлагает использовать CDirectScreenAccess. Он более безопасен и лишен описанных недостатков, но все еще достаточно быстр. CDirectScreenAccess поддерживает связь с сервером окна с помощью двух уведомлений:
Ниже приведен пример, иллюстрирующий работу через CDirectScreenAccess.
// Унаследован от MDirectScreenAccess void CMyGameView::Restart(RDirectScreenAccess::TTerminationReasons aReason) { // Обычно просто перезапускается прямой доступ к экрану TRAPD(err, iMyDrawer->StartL()); if(err!= KErrNone) { // Ошибка при перезапуске } } // Унаследован от MDirectScreenAccess; вызывается, когда необходимо // немедленно запретить прямой доступ void CMyGameView::AbortNow(RDirectScreenAccess::TTerminationReasons aReason) { // Немедленное запрещение доступа к видеопамяти // то есть диалог становится видимым. } // Строим CDirectScreenAccess void CHelloWorldBasicAppView::CreateMyDrawerL() { delete iMyDrawer; iMyDrawer=NULL; iMyDrawer= CDirectScreenAccess::NewL( iEikonEnv->WsSession(), *iEikonEnv->ScreenDevice(), Window(),*this); iEikonEnv->WsSession().Flush(); iMyDrawer->StartL(); iMyDrawer->ScreenDevice()->SetAutoUpdate(ETrue); } // Копируем внеэкранный буфер на экран, используя CDirectScreenAccess void CMyGameView::DisplayBackBuffer()const { iMyDrawer->Gc()->BitBlt( TPoint(0,0), iMyBackBuffer); }
Перед тем как вызывать CDirectScreenAccess::StartL для активизации прямого рисования, буфер клиента сервера окна должен быть очищен. Для того чтобы разрешить автоматическое обновление экрана, нужно вызвать метод устройства экрана SetAutoUpdate с параметром ETrue. После активации поддержки прямого рисования CDirectScreenAccess создает CFbsBitGc графический контекст, который можно использовать для рисования на экране.
Когда другое окно пытается пробиться на передний план, CDirectScreenAccess получает сообщение от сервера о необходимости запрета рисование в видеопамять. CDirectScreenAccess вызывает метод AbortNow полученного класса MDirectScreenAccess, который запрещает доступ к видеопамяти. Чтобы избежать эффекта "загрязнения" экрана, сервер окна не производит рисования, пока не получит подтверждение о прекращении доступа к видеопамяти.
Перевод:aRix