Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: rendering to bitmap differs from rendering to screen

  1. #1
    Junior Member Newbie
    Join Date
    Mar 2004
    Posts
    4

    rendering to bitmap differs from rendering to screen

    I rendered some lines to a bitmap and the same lines directly to screen and the image differs on some graphic-cards. For example on a Geforce 2 MX440 with Microsoft driver everything is fine but if i use the NVIDEA driver the lines differ. On boards with Matrox G400 everything is ok but on boards with ATI Radeon 7000 lines differ too.

    Here's a short example which can be used to reproduce the effect. It draws green circles in a bitmap and displays it on the screen. Then it draws the same circles with red color in the same window. On some PCs you can still see some green points beside the red circles.

    Does anybody know how to avoid the green pixels an all graphicboards?

    #include <windows.h>
    #include <gl/gl.h>
    #include <math.h>

    HBITMAP hbitmap;
    HDC memdc;
    HGLRC hglrc;

    LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM);

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
    {
    WNDCLASS wc;
    MSG msg;
    HWND hWnd;

    if(!hPrevInstance)
    {
    wc.lpszClassName="OpenGLAppClass";
    wc.lpfnWndProc=MainWndProc;
    wc.style=CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
    wc.hInstance=hInstance;
    wc.hIcon=LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor=LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName=NULL;
    wc.cbClsExtra=0;
    wc.cbWndExtra=0;
    RegisterClass(&wc);
    }
    hWnd=CreateWindow("OpenGLAppClass",
    "OpenGL Application",
    WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLING S,
    0,0,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstanc e,NULL);
    ShowWindow(hWnd, nCmdShow);
    while(GetMessage(&msg,NULL,0,0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return msg.wParam;
    }


    void InitGL(HWND hwnd)
    {
    RECT rect;

    GetClientRect(hwnd,&rect);
    glViewport(0,0,rect.right,rect.bottom);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glOrtho((GLdouble) -0.5,(GLdouble) (rect.right-0.5),
    (GLdouble) -0.5,(GLdouble) (rect.bottom-0.5),
    (GLdouble) -1.,(GLdouble) 1.);
    glDrawBuffer(GL_FRONT);
    glShadeModel(GL_FLAT);
    glEnable(GL_LINE_STIPPLE);
    glLineStipple(1,-1);
    glLineWidth(1);
    glFlush();
    }


    #define PI 3.1415926535897932384626433832795
    void DrawGL(HWND hwnd)
    {
    RECT rect;
    int i,ianzs,ix,iy;
    double hr,hxm,hym;
    double xh,yh,hxp,hyp;
    double sinal,cosal;
    double hxa,hya;
    double alpha;

    GetClientRect(hwnd,&rect);
    hxm=((rect.right+rect.left)*0.5);
    hym=((rect.top+rect.bottom)*0.5);
    for(hr=hxm/2;hr>10.;hr-=5.)
    {
    alpha=acos(1.0-0.4/hr);
    if(alpha<0.00001) alpha=0.00001;
    ianzs=(int)((PI+PI)/alpha);
    alpha=(PI+PI)/ianzs;
    sinal=sin(alpha);
    cosal=cos(alpha);
    hxa=hxm+hr;
    hya=hym;
    glBegin(GL_LINE_STRIP);
    ix=(int)(hxa);
    iy=(int)(hya);
    glVertex2i(ix,iy);
    hxp=hxa;
    hyp=hya;
    for(i=1;i<ianzs;i++)
    {
    xh=hxp-hxm;
    yh=hyp-hym;
    hxp=xh*cosal-yh*sinal+hxm;
    hyp=xh*sinal+yh*cosal+hym;
    ix=(int)(hxp);
    iy=(int)(hyp);
    glVertex2i(ix,iy);
    }
    ix=(int)(hxa);
    iy=(int)(hya);
    glVertex2i(ix,iy);
    glEnd();
    }
    glFlush();
    }

    void InitWindow(HWND hwnd)
    {
    PIXELFORMATDESCRIPTOR pfd;
    int iPixelFormat;
    HDC hdc;

    hdc=GetDC(hwnd);
    pfd.nSize=sizeof(pfd);
    pfd.nVersion=1;
    pfd.dwFlags=PFD_DRAW_TO_WINDOW| PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI;
    pfd.cAccumAlphaBits=0;
    pfd.cAccumBits=0;
    pfd.cAccumBlueBits=0;
    pfd.cAccumGreenBits=0;
    pfd.cAccumRedBits=0;
    pfd.cAlphaBits=0;
    pfd.cAlphaShift=0;
    pfd.cAuxBuffers=0;
    pfd.cBlueBits=0;
    pfd.cBlueShift=0;
    pfd.cColorBits=(unsigned char) 32;
    pfd.cDepthBits=32;
    pfd.cGreenBits=0;
    pfd.cGreenShift=0;
    pfd.cRedBits=0;
    pfd.cRedShift=0;
    pfd.cStencilBits=0;
    pfd.dwDamageMask=0;
    pfd.dwLayerMask=0;
    pfd.dwVisibleMask=0;
    pfd.iLayerType=PFD_MAIN_PLANE;
    pfd.iPixelType=PFD_TYPE_RGBA;
    iPixelFormat=ChoosePixelFormat(hdc, &pfd);
    DescribePixelFormat(hdc,iPixelFormat,sizeof(PIXELF ORMATDESCRIPTOR),&pfd);
    SetPixelFormat(hdc,iPixelFormat,&pfd);
    hglrc=wglCreateContext(hdc);
    ReleaseDC(hwnd,hdc);
    }


    void CreateGLBitmap(HWND hwnd)
    {
    int iPixelFormat;
    int ncolor;
    PIXELFORMATDESCRIPTOR pfd;
    BITMAPINFO *biinfo;
    void *lpbits;
    RECT rect;
    int size;
    HGLRC hglrn;
    HDC hdc;

    if(memdc) DeleteDC(memdc);
    if(hbitmap) DeleteObject(hbitmap);
    memdc=NULL;
    hbitmap=NULL;
    GetClientRect(hwnd,&rect);
    hdc=GetDC(hwnd);
    memdc=CreateCompatibleDC(hdc);
    if(!memdc) return;
    iPixelFormat=GetPixelFormat(hdc);
    DescribePixelFormat(hdc,iPixelFormat,sizeof(PIXELF ORMATDESCRIPTOR),&pfd);
    if((pfd.iPixelType==PFD_TYPE_RGBA)&&(pfd.cColorBit s>8))
    ncolor=0;
    else
    ncolor=1<<pfd.cColorBits;
    biinfo=(BITMAPINFO *)malloc(sizeof(BITMAPINFO)+ncolor*sizeof(RGBQUAD) );
    if(biinfo==NULL) return;
    ZeroMemory(biinfo, sizeof(BITMAPINFO));
    biinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    biinfo->bmiHeader.biWidth=rect.right;
    biinfo->bmiHeader.biHeight=rect.bottom;
    biinfo->bmiHeader.biPlanes=1;
    if(pfd.cColorBits<=4)
    biinfo->bmiHeader.biBitCount=4;
    else if(pfd.cColorBits<=8)
    biinfo->bmiHeader.biBitCount=8;
    else if(pfd.cColorBits<=16)
    biinfo->bmiHeader.biBitCount=16;
    else if(pfd.cColorBits<=24)
    biinfo->bmiHeader.biBitCount=24;
    else
    biinfo->bmiHeader.biBitCount=32;
    biinfo->bmiHeader.biCompression=BI_RGB;
    size=biinfo->bmiHeader.biWidth * biinfo->bmiHeader.biBitCount;
    size=((size + 31)/32 * 4);
    biinfo->bmiHeader.biSizeImage=size * biinfo->bmiHeader.biHeight;
    hbitmap=CreateDIBSection(hdc,biinfo,DIB_RGB_COLORS ,
    &lpbits,NULL,(DWORD)0);
    free(biinfo);
    if(!hbitmap) return;
    SelectObject(memdc,hbitmap);
    pfd.nSize=sizeof(pfd);
    pfd.nVersion=1;
    pfd.dwFlags=PFD_DRAW_TO_BITMAP| PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI;
    pfd.cAccumAlphaBits=0;
    pfd.cAccumBits=0;
    pfd.cAccumBlueBits=0;
    pfd.cAccumGreenBits=0;
    pfd.cAccumRedBits=0;
    pfd.cAlphaBits=0;
    pfd.cAlphaShift=0;
    pfd.cAuxBuffers=0;
    pfd.cBlueBits=0;
    pfd.cBlueShift=0;
    pfd.cColorBits=(unsigned char) biinfo->bmiHeader.biBitCount;
    pfd.cDepthBits=32;
    pfd.cGreenBits=0;
    pfd.cGreenShift=0;
    pfd.cRedBits=0;
    pfd.cRedShift=0;
    pfd.cStencilBits=0;
    pfd.dwDamageMask=0;
    pfd.dwLayerMask=0;
    pfd.dwVisibleMask=0;
    pfd.iLayerType=PFD_MAIN_PLANE;
    pfd.iPixelType=PFD_TYPE_RGBA;
    iPixelFormat=ChoosePixelFormat(memdc, &pfd);
    DescribePixelFormat(memdc,iPixelFormat,sizeof(PIXE LFORMATDESCRIPTOR),&pfd);
    SetPixelFormat(memdc,iPixelFormat,&pfd);
    hglrn=wglCreateContext(memdc);
    wglMakeCurrent(memdc,hglrn);
    InitGL(hwnd);
    glClearColor(0.,0.,1.,0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f((GLfloat)0.0,(GLfloat)1.0,(GLfloat)0.0);
    DrawGL(hwnd);
    wglDeleteContext(hglrn);
    ReleaseDC(hwnd,hdc);
    }


    LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
    {
    PAINTSTRUCT ps;
    HDC hdc;

    switch(msg)
    {
    case WM_CREATE:
    InitWindow(hwnd);
    CreateGLBitmap(hwnd);
    break;
    case WM_PAINT:
    hdc=BeginPaint(hwnd,&ps);
    if(memdc) BitBlt(hdc,ps.rcPaint.left,ps.rcPaint.top,
    ps.rcPaint.right-ps.rcPaint.left,ps.rcPaint.bottom-ps.rcPaint.top,
    memdc,ps.rcPaint.left,ps.rcPaint.top,SRCCOPY);
    wglMakeCurrent(hdc,hglrc);
    InitGL(hwnd);
    glColor3f((GLfloat)1.0,(GLfloat)0.0,(GLfloat)0.0);
    DrawGL(hwnd);
    wglMakeCurrent(NULL,NULL);
    EndPaint(hwnd,&ps);
    break;
    case WM_DESTROY:
    if(hglrc)
    {
    wglMakeCurrent(NULL,NULL);
    wglDeleteContext(hglrc);
    }
    if(memdc) DeleteDC(memdc);
    if(hbitmap) DeleteObject(hbitmap);
    PostQuitMessage(0);
    break;
    case WM_SIZE:
    CreateGLBitmap(hwnd);
    default:
    return(DefWindowProc(hwnd, msg, wParam, lParam));
    }
    return 0;
    }

  2. #2
    Intern Contributor
    Join Date
    Feb 2004
    Posts
    98

    Re: rendering to bitmap differs from rendering to screen

    You can't, because you can't control where the rendering occurs (in hardware or software). And that is a likely source of the precision errors.

    The only time OpenGL is guaranteed to give the same (pixel-exact) results is to render into the same target with the same command sequence. The bitmap and the screen are different targets.

  3. #3
    Junior Member Regular Contributor
    Join Date
    Jun 2003
    Location
    USA
    Posts
    117

    Re: rendering to bitmap differs from rendering to screen

    Depending on the resolution you were trying to achieve in the bitmap rendering, you could always render to a back buffer of the display and copy the result to your bitmap.

    Since the rendering target is the same as the display the bitmap should be identical to the display.

  4. #4
    Junior Member Newbie
    Join Date
    Mar 2004
    Posts
    4

    Re: rendering to bitmap differs from rendering to screen

    Originally posted by robosport:
    Depending on the resolution you were trying to achieve in the bitmap rendering, you could always render to a back buffer of the display and copy the result to your bitmap.

    Since the rendering target is the same as the display the bitmap should be identical to the display.
    Yes, but how do I copy the back buffer to a bitmap? All I can do with the back buffer is to swap it into the front buffer but I can't define another target.

  5. #5
    Senior Member OpenGL Pro
    Join Date
    Feb 2002
    Location
    Bonn, Germany
    Posts
    1,652

    Re: rendering to bitmap differs from rendering to screen

    You can't render to a bitmap and have hardware acceleration. That's software emulation, and rendering gets done by Microsoft's rusty old software GL implementation.

    That's also the reason why you see no difference compared to the Geforce 2 MX with "Microsoft driver", because the card doesn't render anything in that case, it just displays the result.

    I suspect it's the same thing with the Matrox G400. I've seen Matrox cards catastrophically fail at all sorts of simple things related to OpenGL. Wouldn't surprise me at all if you in fact got Microsoft's software implementation again.

    You read the back buffer with glReadPixels. Note that this only works reliably if the window is completely visible (not obscured by other windows). If you want to handle that case, you need pbuffers.

  6. #6
    Junior Member Newbie
    Join Date
    Mar 2004
    Posts
    4

    Re: rendering to bitmap differs from rendering to screen

    I changed the Pixelformat-Flag in both cases to
    pfd.dwFlags=PFD_DRAW_TO_BITMAP| PFD_DRAW_TO_WINDOW| PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI;
    Now the same rendering-contexts are chosen and it works. But all rendering is now done by software.
    GlReadPixel (much to slow) or a bitblt (which is much faster) is no solution because parts of the window are obscured by other windows.
    Pbuffers are also no solution because most cards (e.g. all cards I mentioned in my first post) don't support pbuffers.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •