优化用gdi渲染的engine的速度

来源:互联网 发布:java逆波兰式算法 编辑:程序博客网 时间:2024/04/30 06:22

我原来的代码是这么写的

HDC hdc,hMemDC;

hMemDC = ::CreateCompatibleDC(hdc);

HBITMAP hbmp = ::CreateCompatibleBitmap(hdc);

HBITMAP holdbmp = ::SelectObject(hMemDC,hbmp);

//draw something on the memory dc

::SetPixel(hMemDC,x,y,RGB(r,g,b);

BitBlt(hdc,...,hMemDC...);

::SelectObject(hMemDC,hOldbmp);

DeleteObject(hbmp);

DeleteDC(hMemDC);

 一般的绘图都是这么干。本来我以为setpixel的第1个参数传memdc应该会快点,以为是用的直接象素存取。实际

上它做的事情远不是这么点,看书上实现,先要取得dc的属性,然后还有一些事情要做,最后才给象素上色,

应该还有个状态转换,能不慢嘛。书上说的比较快的方法是用CreateDibSection  这个来做。这样就可以在用户态

进行直接象素存取了。速度应该是原来的好几倍(应该会在10倍以上)。mesa里面的代码就这么干的。我把它摘抄下来。

 

struct wmesa_framebuffer
{
    struct gl_framebuffer Base;
    HDC                 hDC;
    int   pixelformat;
    GLuint  ScanWidth;
    BYTE  cColorBits;
    /* back buffer DIB fields */
    HDC                 dib_hDC;
    BITMAPINFO          bmi;
    HBITMAP             hbmDIB;
    HBITMAP             hOldBitmap;
    PBYTE               pbPixels;
    struct wmesa_framebuffer *next;
};

typedef struct wmesa_framebuffer *WMesaFramebuffer;

BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize)
{
    HDC          hdc = pwfb->hDC;
    LPBITMAPINFO pbmi = &(pwfb->bmi);
    HDC          hic;

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = lxSize;
    pbmi->bmiHeader.biHeight= -lySize;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL);
    pbmi->bmiHeader.biCompression = BI_RGB;
    pbmi->bmiHeader.biSizeImage = 0;
    pbmi->bmiHeader.biXPelsPerMeter = 0;
    pbmi->bmiHeader.biYPelsPerMeter = 0;
    pbmi->bmiHeader.biClrUsed = 0;
    pbmi->bmiHeader.biClrImportant = 0;
   
    pwfb->cColorBits = pbmi->bmiHeader.biBitCount;
    pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3;
   
    hic = CreateIC("display", NULL, NULL, NULL);
    pwfb->dib_hDC = CreateCompatibleDC(hic);
   
    pwfb->hbmDIB = CreateDIBSection(hic,
       &pwfb->bmi,
       DIB_RGB_COLORS,
       (void **)&(pwfb->pbPixels),
       0,
       0);
    pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB);
   
    DeleteDC(hic);

    wmSetPixelFormat(pwfb, pwfb->hDC);
    return TRUE;
}

static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC)
{
    pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL);

    // Only 16 and 32 bit targets are supported now
    assert(pwfb->cColorBits == 0 ||
    pwfb->cColorBits == 16 ||
    pwfb->cColorBits == 32);

    switch(pwfb->cColorBits){
    case 8:
 pwfb->pixelformat = PF_INDEX8;
 break;
    case 16:
 pwfb->pixelformat = PF_5R6G5B;
 break;
    case 32:
 pwfb->pixelformat = PF_8R8G8B;
 break;
    default:
 pwfb->pixelformat = PF_BADFORMAT;
    }
}

static wmDeleteBackingStore(WMesaFramebuffer pwfb)
{
    if (pwfb->hbmDIB) {
 SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap);
 DeleteDC(pwfb->dib_hDC);
 DeleteObject(pwfb->hbmDIB);
    }
}


这样原来的setpixel可以这么写了

#define BGR16(r,g,b) (  (((unsigned short)b       ) >> 3) | /
                        (((unsigned short)g & 0xf8) << 2) | /
                        (((unsigned short)r & 0xf8) << 7) )

#define BGR32(r,g,b) (unsigned long)((DWORD)(((BYTE)(b)| /
                                    ((WORD)((BYTE)(g))<<8))| /
                                    (((DWORD)(BYTE)(r))<<16)))

#define WMSETPIXEL16(pwc, y, x, r, g, b) { /
LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); /
*lpw = BGR16((r),(g),(b)); }

#define WMSETPIXEL32(pwc, y, x, r, g, b) { /
LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); /
*lpdw = BGR32((r),(g),(b)); }

 

void SetPixel(WMesaFramebuffer pwfb,int x,int y,DWORD clr)

{

  if(pwfb->pixelformat == PF_5R6G5B){

      WMSETPIXEL16(pwfb,x,pwfb->y,clr);

}

else if(pwfb->pixelformat ==PF_8R8G8B){

 WMSETPIXEL32(pwfb,x,y,clr);

}

}

以前有个裂缝。后来看书说是要遵守一个填充规则。比较重要的一点是刚开始的时候一定全部转浮点数进去,到

最后一步再转成int。这样结果就会比较理想。昨天把纹理改了下。现在基本上算比较完善了。速度也还可以。

这周基本上就可以做完原来的计划了。

原创粉丝点击