如何加快屏幕显示速度 [英] How Can I Speed Up Screen Display

查看:93
本文介绍了如何加快屏幕显示速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试加速生成分形对象并显示它们的例程。我希望它不会超过40毫秒。我现在在800毫秒。



我正在计算像素颜色值并将它们插入到整个客户区的GDI位图中,如下面的简化代码所示。



据我所知,用GetCurrentTime()测量经过的时间大约是计算像素颜色(400毫秒)的一半时间。花费一半的时间将像素颜色写入位图(400毫秒)。将位图绘制到客户区域需要少于1毫秒。



有人请告诉我如何在比BitPixel更短的时间内将颜色数据放入位图中。直接写入屏幕时,SetPixel非常慢。我知道每次执行时都必须与显示适配器进行颜色匹配,在我的中分辨率显示适配器上大约需要500,000次。我希望在写入位图时不会有颜色匹配。我期待一些延迟将位图绘制到屏幕上。看起来我两个都错了。



我使用的代码比这个稍微复杂一点,但它说明了问题



程序中先前声明的变量:

I am trying to speed up a routine that generate fractal objects and displays them. I want it to take no more that 40 msec. I am presently at 800 msec.

I am calculating pixel color values and inserting them into a GDI bitmap of the whole client area, as shown in the simplified code below.

As far as I can tell by measuring lapsed time with GetCurrentTime() about half the time is spent calculating pixel color (400 msec). Half the time is spent writing the pixel color into the bitmap(400 msec). Painting the bitmap to the client area takes less 1 msec.

Will someone please advise me as to how I can put the color data in the bitmap in less time than SetPixel takes. SetPixel is notoriously slow when writing directly to the screen. I understand it has to do a color match with the display adapter each time it is executed, about 500,000 times on my mid-resolution display adapter. I was hoping there would be no color matching when writing to the bitmap. And I was expecting some delay painting the bitmap to the screen. Looks like I was wrong on both counts .

I am using a slightly more complicated code than this but it illustrates the problem

Variables declared earlier in the program:

static double  maxFractalX, minFractalX, maxFractalY, minFractalY; // fractal set dimensions
static  int        maxX,maxY,maxI;   //client area dimensions in pixels 







case WM_PAINT:

    int x,y;
    HDC hdc,hdcMem;
    HBITMAP hBitMap; 
    double FractalX, FractalY;

    hdc = BeginPaint(hWnd, &ps);
    hdcMem=CreateCompatibleDC(hdc);
    hBitMap=CreateCompatibleBitmap(hdc, maxX, maxY);
    SelectObject(hdcMem,hBitMap); 

    for (y = 0; y < maxy; y++)
    {
        FractalY = minFractalY + (maxFractalY-minFractalY)*y/(maxY-1);
        for (x = 0; x < maxx; x++)
        {
            FractalX = minFractalX + (maxFractalX-minFractalX)*x/(maxX-1);
            i = ValidateMandelbrotElement(FractalX, FractalY, maxI);
            //determines if the fractal element represented by this pixel diverges. If so, how fast?
            SetPixel(hdcMem, x, y, RGB(a,b,c)); // a,b,c keyed to I 
            //How can I replace this statement with something much faster?
        }
    }
    BitBlt(hdc,0,0,maxX,maxY,hdcMem,0,0,SRCCOPY); //Surprisingly fast
    DeleteDC(hdcMem);
    DeleteObject(hBitMap);
    EndPaint(hWnd, &ps);
    break;

推荐答案

Gday,刚刚玩过我自己分了几个星期,4d julia设置在我的情况下 - 你提到的问题是追求的明确问题之一。



这样做的方法是分配一个缓冲区,它将保存您想要绘制的像素的rgba值。您几乎可以立即访问像素。



为了进一步加快程序速度,您应该使用工作线程。每个线程在发出信号完成之前完成图片的一部分。每个线程都可以使用相同的屏幕缓冲区,然后您可以一次性地进行屏幕爆炸。



这里是基本代码:



Gday, just been playing with fractals myself for a couple of weeks, 4d julia sets in my case - the problems you mention are one of the definite gotchas in the pursuit.

The way to do it is to allocate a buffer that will hold the rgba values of the pixels you wish to plot. You can access the pixels in virtually no time.

In order to further speed up your program, you should use worker threads. Each thread completes a portion of the picture before signalling that it''s done. Each thread can use the same screen buffer, which you then blast to screen in a single fell swoop.

Here''s the basic code:

void *screenBuffer;
long imageWidth, imageHeight;

void setupBuffer(int w, int h)
{
    screenBuffer = (long*)malloc(w * h * 4); //sizeof(long));
    imageWidth = w;
    imageHeight = h;
}

void myPixel(int x, int y, long rgbaVal)
{
    ((long*)(screenBuffer))[y*imageWidth+x] = rgbaVal; //myPos[y*imageWidth + x] =  rgbaVal;
}

// uncomment as needed
//#define BYTE unsigned char
//#define RGBA(r,g,b,a) ((unsigned int)((BYTE)(b)|((BYTE)(g) << 8)|((BYTE)(r) << 16)|(BYTE)(a)))

// blit a 32bit buffer to a window
void videoput32(void *buf, int imgBufWidth, int imgBufHeight, HWND destHwnd)
{
    char bibuf[ sizeof(BITMAPINFOHEADER)+12 ];
    BITMAPINFO &bi = *(BITMAPINFO*)&bibuf;
    BITMAPINFOHEADER &bih = bi.bmiHeader;
    bih.biSize = sizeof(bih);
    bih.biWidth = imgBufWidth;
    bih.biHeight = -imgBufHeight;
    bih.biPlanes = 1;
    bih.biBitCount = 32;
    bih.biCompression = BI_BITFIELDS;
    bih.biSizeImage = 0;
    bih.biXPelsPerMeter = 0;
    bih.biYPelsPerMeter = 0;
    bih.biClrUsed = 0;
    bih.biClrImportant=0;
//  ((unsigned long*)bi.bmiColors)[0] = 0;
    ((unsigned long*)bi.bmiColors)[0]=0x00FF0000;
    ((unsigned long*)bi.bmiColors)[1]=0x0000FF00;
    ((unsigned long*)bi.bmiColors)[2]=0x000000FF;
    RECT r;
    HDC dc=GetDC(destHwnd);
    GetClientRect(destHwnd, &r);
    StretchDIBits(dc, 0, 0, r.right, r.bottom, 0, 0, imageWidth, imageWidth, buf, &bi, DIB_RGB_COLORS, SRCCOPY);
    ReleaseDC(destHwnd,dc);
    ValidateRect(destHwnd, &r);
}







来自DialogProc的一小部分:




And a small section from the DialogProc:

case WM_COMMAND:
            {
                switch(LOWORD(wParam))
                {
                case IDC_RENDER_BTN:
                    threadsRemaining = onRenderButtonClick();
                    SetDlgItemInt(hwndDlg, IDC_THREADS_REMAINING_TXT, threadsRemaining, true);
                    break;
                }
            }
            return TRUE;

        case WM_THREAD_COMPLETE:
            threadsRemaining--;
            SetDlgItemInt(hwndDlg, IDC_THREADS_REMAINING_TXT, threadsRemaining, true);
            if (threadsRemaining == 0)
            {
                 drawZbufferToImage();
                 SendMessage(outputWnd, WM_SET_DATA, 0, (LPARAM) &bufferSpec);

                 threadsRemaining = onRenderButtonClick();
            }
            break;





另一个 - 一个线程函数的片段,它告诉主窗口它已完成。



And another - a snippet of the thread function and it telling the main window that it''s done.

#define WM_THREAD_COMPLETE WM_USER + 1
void threadFunction2(void *threadData)
{
//  printf("threadFunction2\n");
  myThreadData_t *tmp = (myThreadData_t*)threadData;

  drawIntoZbuffer3( frameNum, (RECT){tmp->left,tmp->top,tmp->right,tmp->bottom} );
  SendMessage(mainHwnd, WM_THREAD_COMPLETE, 0, 0);
}


你可以使用directx将像素绘制到后备缓冲区。这将在GPU(图形处理单元)上完成,其将比setpixel快得多。你真的只需要初始化directx,创建一个窗口,设置d3dpresent参数,锁定后备缓冲区并使用数组符号设置像素。



GDI是慢的。



如果你想将图像渲染到后台缓冲区,你也可以使用GDI。



只是一个建议。



如果你想要快速像素绘图,我也推荐像素烤面包机。谷歌,你会发现。
you could use directx to plot pixels to a backbuffer. This would be done on the GPU (graphics processing unit) which would be significantly faster than setpixel. You would really just have to initialize directx, create a window, set d3dpresent parameters, lock the backbuffer and set the pixels using the array notation.

GDI is SLOW.

if you wanted to render images to the backbuffer, you can also use the GDI for this.

just a suggestion.

if you want fast pixel plotting, I recommend pixel toaster too. google it and you will find.


这篇关于如何加快屏幕显示速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆