问题描述
我的GDI程序在Windows XP上运行良好,但在Windows Vista和7它看起来很可怕,由于缺乏GDI硬件加速。我回忆起几年前读一篇文章说,Windows 7添加了硬件加速到一些GDI函数,包括BitBlt()函数。据推测,如果你绘制到一个内存位图,然后使用BitBlt()来复制图像到你的主窗口,它运行的速度与XP相同的速度。是真的吗?
My GDI program runs fine on Windows XP but on Windows Vista and 7 it looks pretty terrible due to the lack of GDI hardware acceleration. I recall reading an article a few years back saying that Windows 7 added hardware acceleration to some GDI functions, including BitBlt() function. Supposedly, if you if you draw to a memory bitmap and then use BitBlt() to copy the image to your main window it runs about the same speed as XP. Is that true?
如果是真的,你该怎么办?我很可怕的编程,我有一点麻烦。我创建了下面的类来尝试并使其工作:
If it is true, how do you do it? I'm terrible at programming and am having a bit of trouble. I created the below class to to try and get it working:
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()函数中添加了一行:
In the OnPaint() function of the window I added the line:
pDC->BitBlt(2, 2, 100, 100, &m_MemBmp, 0, 0, SRCCOPY);
我希望在窗口的一角看到一个100x100的黑盒, 。我可能正在做一切可怕的错误,所以如果有人可以告诉我如何正确地做这件事,非常感谢。
I was hoping to see a 100x100 black box in the corner of the window but it didn't work. I'm probably doing everything horrifically wrong, so would be grateful if somebody could advise me as to how to do this correctly.
感谢您提供任何建议。 / p>
Thanks for any advice you can offer.
推荐答案
AFAIK您在所有版本的Windows上的GDI函数中获得硬件加速(如果有人可以解释它更详细)。但无论如何,你是正确的双缓冲(这是你说的)提供了一个巨大的性能提升(更重要的是没有闪烁)相对于直接绘制到屏幕。
AFAIK you get hardware acceleration on GDI functions on all versions of Windows (I'm happy to stand corrected on this if someone can explain it in more detail). But either way, you're correct that double buffering (which is what you're talking about) provides a massive performance boost (and more importantly no flickering) relative to drawing direct to the screen.
我做了很多这样的工作,并提出了一个方法,允许你在绘图功能的同时使用GDI和GDI +,但受益于BitBlt的绘图硬件加速向屏幕。 GDI +不是硬件加速的AFAIK,但是在许多更复杂的绘图技术中非常有用,所以它可以有用的选项。
I've done quite a lot of this and have come up with a method to allow you to use GDI and GDI+ at the same time in your drawing functions, but benefit from the hardware acceleration of the BitBlt in drawing to screen. GDI+ isn't hardware accelerated AFAIK but can be very useful in many more complex drawing techniques so it can be useful to have the option of.
所以,我的基本视图类将有以下成员:
So, my basic view class will have the following members :
Graphics *m_gr;
CDC *m_pMemDC;
CBitmap *m_pbmpMemBitmap;
然后类本身将会有这样的代码
Then the class itself will have code something like this
/*======================================================================================*/
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(),这是更方便的方式,我使用它。你需要在OnSize()中调用vCreateScreenBuffer()。
So, you can then either just draw direct to the memory DC and call InvalidateRect() or put all your drawing code in rcUpdateBitmap() which was more convenient for the way I was using it. You'll need to call vCreateScreenBuffer() in OnSize().
希望能给你一些想法。双缓冲绝对是去速度和非闪烁UI的方式。它可以采取一些努力去,但它是绝对值得的。
Hopefully that gives you some ideas anyway. Double buffering is definitely the way to go for speed and non-flickering UI. It can take a little bit of effort to get going but it's definitely worth it.
这篇关于GDI加速在Windows 7 /绘图到内存位图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!