Ускорение GDI в Windows 7 / Растровые рисунки в память

Моя программа GDI отлично работает в Windows XP, но в Windows Vista и 7 она выглядит довольно ужасно из-за отсутствия аппаратного ускорения GDI. Я вспоминаю, как несколько лет назад читал статью о том, что в Windows 7 добавлено аппаратное ускорение для некоторых функций GDI, включая функцию BitBlt (). Предположительно, если вы рисуете в битовую карту памяти, а затем используете BitBlt () для копирования изображения в главное окно, оно работает с той же скоростью, что и XP. Это правда?

Если это правда, как ты это делаешь? Я ужасно разбираюсь в программировании и у меня возникли некоторые проблемы. Я создал класс ниже, чтобы попытаться заставить его работать:

class CMemBmpTest
{
private: 
    CDC         m_dcDeviceContext;
    CBitmap     m_bmpDrawSurface;

public:
    CMemBmpTest();
    ~CMemBmpTest();
    void Init();
    void Draw();
};

CMemBmpTest::CMemBmpTest()
{
}

CMemBmpTest::~CMemBmpTest()
{
    m_bmpDrawSurface.DeleteObject();
    m_dcDeviceContext.DeleteDC();
}

void CMemBmpTest::Init()
{  
    m_dcDeviceContext.CreateCompatibleDC(NULL);
    m_bmpDrawSurface.CreateCompatibleBitmap(&m_dcDeviceContext, 100, 100);
}

void CMemBmpTest::Draw()
{  
    m_dcDeviceContext.SelectObject(I.m_brshRedBrush);
    m_dcDeviceContext.PatBlt(0, 0, 100, 100, BLACKNESS);
}

В функции окна OnPaint () я добавил строку:

pDC->BitBlt(2, 2, 100, 100, &m_MemBmp, 0, 0, SRCCOPY);

Я надеялся увидеть черный ящик 100х100 в углу окна, но он не сработал. Я, наверное, все делаю ужасно неправильно, поэтому был бы признателен, если бы кто-нибудь посоветовал мне, как сделать это правильно.

Спасибо за любой совет, который вы можете предложить.

 Roel06 июн. 2012 г., 14:29
Если единственное, что вы хотите сделать, - это двойная буферизация (я не совсем понимаю ваш вопрос, но я думаю, что это именно то, что вам нужно), то вам гораздо лучше использовать CMemDC, который занимает всего 2 или 3 строки код, который нужно добавить к своему методу OnPaint () и вуаля, вы готовы к работе. (ну, ваш рендеринг все еще будет медленным, если вы, конечно, используете SetPixelV () для каждого пикселя ...)
 Roman R.31 мая 2012 г., 22:04
Если вы используете GDI, вы вряд ли выиграете от аппаратного ускорения. По крайней мере, в любой разумной степени. Чего стоит сделать, так это просмотреть ваш код и очистить его, чтобы удалить различные виды чрезмерной обработки. Вы также можете попробовать отключить Aero, чтобы, возможно, вернуться к «классическому». GDI (в отличие от реализации поверх Direct3D).

Ответы на вопрос(2)

Решение Вопроса

AFAIK, вы получаете аппаратное ускорение для функций GDI во всех версиях Windows (я буду рад исправить это, если кто-то сможет объяснить это более подробно). Но в любом случае вы исправляете двойную буферизацию (о чем вы говорите), что обеспечивает значительное повышение производительности (и, что более важно, отсутствие мерцания) по сравнению с рисованием непосредственно на экране.

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

Итак, мой базовый класс представления будет иметь следующие члены:

Graphics *m_gr;
CDC *m_pMemDC;
CBitmap *m_pbmpMemBitmap;

Тогда сам класс будет иметь такой код

    /*======================================================================================*/
    CBaseControlPanel::CBaseControlPanel()
    /*======================================================================================*/
    { 
        m_pMemDC = NULL;
        m_gr = NULL;
        m_pbmpMemBitmap = NULL;
    }

    /*======================================================================================*/
    CBaseControlPanel::~CBaseControlPanel()
    /*======================================================================================*/
    {
        // Clean up all the GDI and GDI+ objects we've used
        if(m_pMemDC)
        { delete m_pMemDC; m_pMemDC = NULL; }
        if(m_pbmpMemBitmap)
        { delete m_pbmpMemBitmap; m_pbmpMemBitmap = NULL; }
        if(m_gr)
        { delete m_gr; m_gr = NULL; }
    }   

/*======================================================================================*/
void CBaseControlPanel::OnPaint()
/*======================================================================================*/
{
    pDC->BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(),
                        m_pMemDC, rcUpdate.left, rcUpdate.top, SRCCOPY);
}

/*======================================================================================*/
void CBaseControlPanel::vCreateScreenBuffer(const CSize szPanel, CDC *pDesktopDC)
// In : 
//      szPanel = The size that we want the double buffer bitmap to be
// Out : None
/*======================================================================================*/
{
    // Delete anything we're already using first
    if(m_pMemDC)
    {
        delete m_gr;
        m_gr = NULL;
        delete m_pMemDC;
        m_pMemDC = NULL;
        delete m_pbmpMemBitmap;
        m_pbmpMemBitmap = NULL;
    }
    // Make a compatible DC
    m_pMemDC = new CDC;
    m_pMemDC->CreateCompatibleDC(pDesktopDC);           
    // Create a new bitmap
    m_pbmpMemBitmap = new CBitmap;
    // Create the new bitmap
    m_pbmpMemBitmap->CreateCompatibleBitmap(pDesktopDC, szPanel.cx, szPanel.cy);
    m_pbmpMemBitmap->SetBitmapDimension(szPanel.cx, szPanel.cy);
    // Select the new bitmap into the memory DC
    m_pMemDC->SelectObject(m_pbmpMemBitmap);
    // Then create a GDI+ Graphics object
    m_gr = Graphics::FromHDC(m_pMemDC->m_hDC);
    // And update the bitmap
    rcUpdateBitmap(rcNewSize, true);
}

/*======================================================================================*/
CRect CBaseControlPanel::rcUpdateBitmap(const CRect &rcInvalid, const bool bInvalidate, const bool bDrawBackground /*=true*/)
// Redraws an area of the double buffered bitmap
// In : 
//      rcInvalid - The rect to redraw
//      bInvalidate - Whether to refresh to the screen when we're done
//      bDrawBackground - Whether to draw the background first (can give speed benefits if we don't need to)
// Out : None
/*======================================================================================*/
{
   // The memory bitmap is actually updated here

   // Then make the screen update
   if(bInvalidate)
   { InvalidateRect(rcInvalid); }
}

Таким образом, вы можете либо просто рисовать прямо в DC памяти и вызывать InvalidateRect (), либо поместить весь свой код рисования в rcUpdateBitmap (), что было более удобно для того, как я его использовал. Вам необходимо вызвать vCreateScreenBuffer () в OnSize ().

Надеюсь, это даст вам некоторые идеи в любом случае. Двойная буферизация - определенно способ получить быстрый и не мерцающий интерфейс. Может потребоваться немного усилий, чтобы начать работу, но это определенно стоит того.

 01 июн. 2012 г., 00:33
GDI не ускоряется в Vista, его снова добавили в 7 с помощью WDDM 1.1 (ускорено не все, только небольшой набор функций, см.msdn.microsoft.com/en-us/library/windows/hardware/…)
 01 июн. 2012 г., 09:38
Хорошо, спасибо за информацию об аппаратном ускорении, я не знал об этом. Еще один совет по скорости рисования - GDI + НАМНОГО медленнее, чем GDI для многих вещей, особенно для растровых копий. Вот почему я сохраняю указатели на контекст устройства GDI и GDI +, поэтому я использую GDI + только тогда, когда я не могу найти способ сделать то, что я хочу в GDI.
 user142928801 июн. 2012 г., 00:30
Большое спасибо за подробный ответ. Я постараюсь, чтобы это работало на выходных. Что касается ускорения GDI, то, согласно записи графического интерфейса устройства в Википедии в Windows Vista, «GDI больше не аппаратно ускоряется драйвером видеокарты», в то время как в Windows 7 «Windows 7 включает аппаратное ускорение GDI для операций блитинга». Существует определенная огромная разница в производительности под Vista и 7 по сравнению с XP. Надеюсь, как только я изменю его на двойную буферизацию, он будет работать быстрее, и я наконец смогу переключиться на Windows 7. Еще раз спасибо за ответ.

Ваш ответ на вопрос