GDI加速在Windows 7 /绘制到内存位图(GDI Acceleration In Windo

2019-06-25 01:14发布

我的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);

我希望看到在窗口的角落100x100的黑盒子,但没有奏效。 我可能做的一切惊人,错误的,所以将不胜感激,如果有人能告诉我关于如何正确地做到这一点。

感谢您能提供任何意见。

Answer 1:

据我所知你对所有版本的Windows GDI功能的硬件加速(我很高兴这个来指正,如果有人能详细解释)。 但无论哪种方式,你是正确的,双缓冲(这是你在说什么)提供了一个巨大的性能提升(更重要的是没有闪烁)相对于直接在屏幕上绘图。

我在绘制屏幕做了相当多的这一点,并想出了一个方法,让你使用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()在筛上部分()。

希望这反正给你一些想法。 双缓冲是肯定要走的速度和无闪烁的用户界面的方式。 它可以采取的努力,得到去一点点,但它绝对是值得的。



Answer 2:

CMemDC类: http://www.codeproject.com/Articles/33/Flicker-Free-Drawing-In-MFC http://msdn.microsoft.com/en-us/library/cc308997(v=vs.90)。 ASPX



文章来源: GDI Acceleration In Windows 7 / Drawing To Memory Bitmap
标签: c++ mfc gdi