Сообщений 6    Оценка 25        Оценить  
Система Orphus

Устранение мерцания в GDI+

Автор: Антонов Николай
Источник: RSDN Magazine #5-2004
Опубликовано: 17.04.2005
Исправлено: 21.04.2005
Версия текста: 1.0
Двойная буферизация с использованием GDI+
Двойная буферизация с использованием GDI

Исходные тексты к статье

Двойная буферизация с использованием GDI+

В статье Виталия Брусенцева GDI+: графика нового поколения приводится пример устранения мерцания при помощи двойной буферизации в Win32 приложении (Demo.exe):

void OnPaint(HDC hdc, RECT& rc)
{
    Graphics g(hdc);
    Rect paintRect(0, 0, rc.right, rc.bottom);
    Bitmap backBuffer(rc.right, rc.bottom, &g);
    Graphics temp(&backBuffer);
    PaintBackground(temp, paintRect);
    PaintFlower(temp, paintRect);
    PaintBatterfly(temp, paintRect);
    g.DrawImage(&backBuffer, 0, 0, 0, 0, rc.right, rc.bottom, UnitPixel);
}

Я попробовал написать однооконное MFC приложение, которое рисовало бы то же самое, что и в примере Виталия Брусенцова Demo.exe (бабочка, летящая за цветком). В этом случае функция OnPaint() выглядит так:

Пример Anim1.
void CAnim1View::OnPaint()
{    
    CPaintDC dc(this); 
    // TODO: Add your message handler code here
    Graphics g(this->m_hWnd,true);

    Bitmap backBuffer(winRect.right, winRect.bottom, &g);
    Graphics temp(&backBuffer);

    OnDrawMy(temp);

    g.DrawImage(&backBuffer, 0, 0, 0, 0, winRect.right, winRect.bottom, UnitPixel);
}

Где функция OnDrawMy(Graphics& g) для рисования в стиле GDI+:

void CAnim1View::OnDrawMy(Graphics& g){
    // Рисование в стиле GDI+
    if(bBackGround){
        WCHAR text[]=L"Демонстрация работы \n"
                    L"с прозрачными \n"
                    L"и анимированными \n"
                    L"файлами формата GIF.";
	    HatchBrush brush(HatchStyleCross, 
		    Color(255, 140, 140, 255), 
		    Color(255, 200, 200, 200));
	    g.FillRectangle(&brush,winRectF);

	    Font font(L"Arial", 20);
        SolidBrush textBrush1(Color(180, 0, 0, 255));
	    StringFormat stringFormat1;
        stringFormat1.SetAlignment(StringAlignmentCenter);
        stringFormat1.SetLineAlignment(StringAlignmentCenter);
	    g.DrawString(text, -1, &font, 
		    PointF((winRectF.Width/2), (winRectF.Height/2)), 
		    &stringFormat1, &textBrush1);
    }
	else g.Clear(Color(255, 255, 255, 255));

    if(pf.X-bpf.X>0) bpf.X++; 
    else bpf.X--;
    if(pf.Y-bpf.Y>0) bpf.Y++; 
    else bpf.Y--;
    if(flower){
        g.DrawImage(flower,pf.X,pf.Y);
    }
	if(image){
		image->SelectActiveFrame(&FrameDimensionTime, activeFrame);
        g.SetInterpolationMode(InterpolationModeHighQualityBicubic);
        g.DrawImage(image,bpf.X, bpf.Y, 
            (REAL)image->GetWidth(), (REAL)image->GetHeight());
        activeFrame=(activeFrame+1)%frameCount;
	}
}

Функция, учитывающая изменение размеров окна:

void CAnim1View::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);

    // TODO: Add your message handler code here
    winRect.SetRect(0,0,cx,cy);
	winRectF = RectF(0,0,(REAL)cx,(REAL)cy);
}

После запуска приложения стало ясно, что FPS (количество кадров в секунду) по сравнению с Win32 приложением несколько снизилось.

Данные приведены в таблице.

Двойная буферизация с использованием GDI

Тогда я попробовал применить двойную буферизацию, используемую в обычном GDI. Для этого использовал объекты CDC *m_pdcDisplayMemory и CBitmap *m_pBitmap. В этом случае конструктор и деструктор CAnim2View:

Пример Anim2.
CAnim2View::CAnim2View()
{
    m_pdcDisplayMemory = 0;//new CDC
    m_pBitmap          = 0;//new CBitmap
	.. ..
}

CAnim2View::~CAnim2View()
{
    if(m_pBitmap)delete m_pBitmap;
    if(m_pdcDisplayMemory) delete m_pdcDisplayMemory;
}

Функция рисования OnPaint():

void CAnim2View::OnPaint()
{    
    CPaintDC dc(this);
	CRect rectUpdate;
    dc.GetClipBox(&rectUpdate);

    CBitmap* pOldBitmap =
        m_pdcDisplayMemory->SelectObject(m_pBitmap);

    m_pdcDisplayMemory->PatBlt(rectUpdate.left, rectUpdate.top,
        rectUpdate.Width(), rectUpdate.Height(), PATCOPY);

    OnDraw(m_pdcDisplayMemory);

    dc.BitBlt(rectUpdate.left, rectUpdate.top,
        rectUpdate.Width(), rectUpdate.Height(),
        m_pdcDisplayMemory, rectUpdate.left, rectUpdate.top,
        SRCCOPY);
}

В этом случае используется также и функция OnDraw(CDC* pDC):

void CAnim2View::OnDraw(CDC* pDC)
{
	.. ..

	Graphics *pgr = Graphics::FromHDC(pDC->m_hDC);
	OnDrawMy(*pgr);
	delete pgr;
}

Функция OnDrawMy(Graphics& g) используется та же, что и в предыдущем примере.

Функция, учитывающая изменение размеров окна:

void CAnim2View::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);

    // TODO: Add your message handler code here
    winSizeX = cx;
    winSizeY = cy;

    if(m_pBitmap)delete m_pBitmap; 
    if(m_pdcDisplayMemory) delete m_pdcDisplayMemory;

    m_pdcDisplayMemory = new CDC;
    m_pBitmap          = new CBitmap;

    CRect winRect(0,0,winSizeX,winSizeY);
    winRectF = RectF(0,0,(REAL)winSizeX,(REAL)winSizeY);

    if (m_pdcDisplayMemory->GetSafeHdc() == NULL) {
      CClientDC dc(this);
      m_pdcDisplayMemory->CreateCompatibleDC(&dc);
      m_pBitmap->CreateCompatibleBitmap(&dc, winRect.right,winRect.bottom);
    }
}

После того, как это было сделано, выяснилось, что перерисовка экрана пошла значительно быстрее. Особенно это заметно, когда отключается отрисовка background. В случае использования двойной буферизации в стиле GDI+ отключение background практически не увеличивает FPS.

То есть, если требуется написать графическое приложение с использованием линий, “резиновых нитей”, небольших картинок и пр. можно использовать удобство GDI+ и двойную буферизацию в стиле GDI.

С отрисовкой backgroundБез background
Demo (Win32)910
Anim1(MFC)55
Anim2(MFC)11100
Pentium 3 833 Мгц, 512 Мб ОЗУ, GeForce2 MX/MX 400 32 Мб, монитор 19”
С отрисовкой backgroundБез background
Demo (Win32)5465
Anim1(MFC)2426
Anim2(MFC)6064
Pentium 4 2.66 Ггц, 512 ОЗУ, GeForce FX 5200 64 МБ, монитор 17”
С отрисовкой backgroundБез background
Demo (Win32)1315
Anim1(MFC)66
Anim2(MFC)1040
Pentium 3 800 Мгц, 384 Мб ОЗУ, S3 Graphics Inc. Savage/IX 8 Мб, монитор 14” (NoteBook IBM)


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 6    Оценка 25        Оценить