本人电脑为双核。
使用一个进程,循环10000000次绘制2条线的时间和2个进程各循环10000000次绘制2条线的时间为什么相差这么大?
每个进程都应该有自己的地址空间,GDI对象都是在各自的进程中创建的。
本以为可以并发绘图,即便无法并发,时间比也应该是2倍啊,但是实际测试结果却有9倍之巨。求高手解疑!!!void CXXXDlg::OnBnClickedButton()
{
SYSTEMTIME time;
GetSystemTime(&time); HDC                 m_hScreenDC = ::GetDC(m_hWnd);
HDC                 m_memdc     = CreateCompatibleDC(m_hScreenDC);
HBITMAP             m_hBit      = CreateCompatibleBitmap(m_hScreenDC,800,600);
HBITMAP             m_hOldBit   = (HBITMAP)SelectObject(m_memdc,m_hBit);
POINT               pt; for(long i = 0;i < 10000000;i++)
{
::MoveToEx(m_memdc,0,0,&pt);
::LineTo(m_memdc,100,100);
::MoveToEx(m_memdc,200,200,&pt);
::LineTo(m_memdc,300,300);
} if(m_memdc)
{
SelectObject(m_memdc,m_hOldBit); ::DeleteDC(m_memdc);
m_memdc = NULL;
} if(m_hBit)
{
DeleteObject(m_hBit);
m_hBit = NULL;
} if(m_hScreenDC)
{
::ReleaseDC(m_hWnd,m_hScreenDC);
m_hScreenDC = NULL;
} SYSTEMTIME time2;
GetSystemTime(&time2);
CString str;
str.Format("%d-%d-%d %d-%d-%d\n",time.wMinute,time.wSecond,time.wMilliseconds,
time2.wMinute,time2.wSecond,time2.wMilliseconds);
AfxMessageBox(str);
}

解决方案 »

  1.   

    gdi对象有很大部分在内核空间,绘图的api也在内核模式
      

  2.   

    一个进程调用绘图api会让其他进程的绘图过程暂停,直到那个api返回。
    绘图过程中调用过程是用的cpu,从用户地址空间到图形驱动程序,但是之后的真正的绘图过程,内部其实是使用的gpu。图形驱动程序通过显卡驱动利用cpu将用户参数传入gpu的相应寄存器,最后发送状态标志到gpu,然后挂起当前线程。gpu处理完之后会唤醒绘图线程的。绘图并不是cpu去做的比如你画一张图片,一种方法利用图片句柄调用api直接绘到dc上,另一种是利用描点函数将图片像素逐个绘到dc上。即使扣除掉调用n次描点函数的传入开销,调api还是要比像素描快n个数量级。这跟你使用多少核的cpu已经关系不大了绘图的话,尽量做到耗时的事情都化整为零,然后就是做到会同样的图形时,调用绘图api的次数越少的算法越好。最好不要去拷问cpu的性能。这样才能充分利用gpu的绘图加速功能。还一个就是为什么两个线程绘图要大大慢于一个线程绘两次图。这是因为通常情况下一个线程里一次绘制过程不会调用很多次绘图api,通常就多达几百条而已(楼主用了上千万次已经是不良设计了),然后至少是长时间的空闲(对于gpu而言)。而考虑到多数窗口程序要求快速的响应,以能尽可能好的适应人的视觉感受。图形架构都对线程内调用图形api做了优化(比如使用的缓冲线程、进程描述表,图形驱动响应客户api可以不经过io管理程序而直接与客户程序通信等技术),代价就是对于多进程同时绘图的性能大打折扣了。
      

  3.   

    1.这里使用的是内存DC,我不知道跟GPU到底有多大关系?如果我使用其他非HDC的图形库呢?是否可以全部依靠CPU?
    2.不同的内存DC,相当于是不同的输出设备,虽然我一个进程(或者线程)调用了百万次的绘线函数(当然我这只是验证,实际项目中可不是这样的),你说“然后至少是长时间的空闲(对于gpu而言)”这个我有点疑惑。
      

  4.   


    只要你调用了绘图函数,就涉及到了gpu的访问。在xp下面,GDI使用的DC位于内存中,在vista下面也位于内存中,但是在显卡显存中有一份DC的拷贝。到了win7下面则位于显存中。仅当显存不够用时才会换页到系统内存。但是一般情况下应用程序是不用关心这些的。我也不明白你为什么放着gpu加速不愿用而非要用cpu去做。但是不管怎样,最终显示结果肯定是要靠gpu才能将画面提交到屏幕上。GDI也好、dx也好还是别的什么都一样。完全绕开gpu是不大可能的(除非你用msdos,只调用处理器int10绘图)。其他的绘图库应该也只是将那些重复的功能封装一下而已。
      

  5.   

    补充一下我说的“然后至少是长时间的空闲”是什么意思:一般的dc绘图程序都是窗口程序是吧?而绘图人物往往是在一个消息响应阶段里,而且要求在很短的时间里完成。这样的话可以及时的响应其他的消息。比如鼠标键盘输入。不然的话你会觉得窗口卡顿。一般情况下绘制的图形也比较简单,所以调用的gdi函数也比较少。像你的例子里那样长时间的锁定一个dc的情况是极少见的(一般都是不良的设计)。你其实可以考虑两种方案的:一种是,如果你的图形确实很复杂但是不会频繁地刷新内容,可以考虑用多线程,也就是另开一个线程用来生成图形。然后本线程内在得到绘图完成的事件时才将得到的图形一次性提交到屏幕上。另一种就是用directx。
      

  6.   

    想完全绕过CPU就按着图片格式把数据写硬盘上
    三维软件里的软件渲染就是这个意思
      

  7.   

    我保存的图片格式可以是BMP,JPG,还可以是PNG,或者PDF,SVG,WPF等,可以的做法是我自己管理像素区,左后保存的时候再分别处理。很明显,自己想做各种绘图效果不是再造轮子?
      

  8.   

    你可以只画bmp然后转换
    用CreateDIBSection创建一个bitmap,并且获取像素的缓冲区,可以自己画,同时可以利用各种gdi的api
      

  9.   

    这个原则上是可以的,——只要你不嫌麻烦。一来各种格式的都可能会要求分别处理。从1位到32位。处理方法不太一样的(msdn文档里有)。二来,内存图片的扫描线是从下往上,而DC的y方向却是从上往下。速度上,你不用api而直接计算坐标填入内存位置的话,速度当然快,但是代码也复杂了(要是没人催你赶工,还是可以接受的),如果你还要兼用gdi api,那又倒退到直接用gdi api的情况了
      

  10.   


    没有引文这些都是现代计算机结构的知识。只要你的机器不是你自己设计的,而是PC市面上都卖的那种。不管是高端还是低端、独立显卡还是集成显卡,都是一样的结构。你非要文档的话,这些都分散在msdn的各个地方,最多的是那些api的说明里面。原理性的东西你都可以自己搜索一下。