2011-01-19 58 views
0

我有一個非常艱難的時間在我的應用程序中整理出這個奇怪的剪切錯誤。基本上,出於某種原因,OpenGL正在剪裁(使用剪刀測試)我的glClear()調用,但不是之後做的渲染。Windows OpenGL實現錯誤?

然而,真正的問題是,當我調整窗口大小時,問題消失。我可以保證調整窗口大小不會改變我的應用程序中的任何內容或運行任何代碼。這非常棒。更糟糕的是,乾脆把

glDisable(GL_SCISSOR_TEST); 
glDisable(GL_SCISSOR_TEST); 

,我需要禁用剪刀測試,而不是僅具有一個調用glDisable()函數解決了這個問題。所以一起刪除代碼(在這個測試用例中,剪刀測試已經被禁用了,但是代碼在這個代碼中沒有在之前的代碼中被禁用)。它甚至解決了這個問題:

glEnable(GL_SCISSOR_TEST); 
glDisable(GL_SCISSOR_TEST); 

只有兩個解釋我能想到。要麼我以某種方式調用UB(我懷疑,因爲opengl沒有UB AFAIK),或者存在實現錯誤,因爲連續調用兩次具有相同參數的glDisable()應該與調用一次相同。如果我沒錯的話。

只是櫃面很感興趣,這裏是該問題發生的功能:

void gle::Renderer::setup3DCamera(gle::CameraNode& cam, gle::Colour bkcol, 
    int clrmask, int skymode, gle::Texture* skytex, bool uselight) { 
    // Viewport 
    Rectangle wr(cam.getViewport()?*cam.getViewport():Rectangle(0,0,1,1)); 
    if (cam.isRatioViewport()||(!cam.getViewport())) { 
     if (i_frameBind==NULL) 
      wr.scale(selectedWindow->getWidth(),selectedWindow->getHeight()); 
     else wr.scale(i_frameBind->getWidth(),i_frameBind->getHeight()); 
    } 
    gle::Rectangle_t<int> iport; iport.set(wr); 
    int winHei; 
    if (i_frameBind==NULL) 
     winHei = selectedWindow->getHeight(); 
    else 
     winHei = i_frameBind->getHeight(); 
    glViewport(iport.x1(),winHei-iport.y2(),iport.wid(),iport.hei()); 
    // Viewport Clipping 
    if (cam.isClipping()) { 
    /* This is never executed in the test case */ 
     glEnable(GL_SCISSOR_TEST); 
     glScissor(iport.x1(),winHei-iport.y2(),iport.wid(),iport.hei()); 
    } else { 
    /* This is where I disable the scissor test */ 
     glDisable(GL_SCISSOR_TEST); 
     glDisable(GL_SCISSOR_TEST); 
    } 
    float w=wr.wid()/2, h=wr.hei()/2; 
    // Projection 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    Projection proj = cam.getProjection(); 
    gluPerspective(proj.fov,proj.aspect*(w/h),proj.cnear,proj.cfar); 
    // Camera 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    float m[] = { 1,0,0,0, 0,0,-1,0, 0,1,0,0, 0,0,0,1 }; 
    glMultMatrixf(m); 
    static gle::Mesh *skyBox = NULL; 
    // Screen Clearing 
    switch (clrmask&GLE_CLR_COLOUR&0x00F?skymode:GLE_SKYNONE) { 
    case GLE_SKYNONE: 
     clear(clrmask&(~GLE_CLR_COLOUR)); break; 
    case GLE_SKYCOLOUR: 
     clearColour(clrmask,bkcol); break; 
    case GLE_SKYBOX: 
     glDisable(GL_DEPTH_TEST); 
     if (!(clrmask&GLE_CLR_DEPTH&0x00F)) glDepthMask(0); 
     float m = (cam.getProjection().cnear+cam.getProjection().cfar)/2.0f; 
     if (skyBox==NULL) skyBox = gle::createStockMesh(GLE_MESHSKYBOX,GLE_WHITE,0,m); 
     glEnable(GL_TEXTURE_2D); 
     glDisable(GL_CULL_FACE); 
     skytex->flush(); 
     glBindTexture(GL_TEXTURE_2D,skytex->getID()); 
     glDisable(GL_LIGHTING); 
     glPushMatrix(); 
     float m3[16]; 
     Orientation::matrixSet(m3,cam.pos().getMatrix(GLE_ROTMATRIX)); 
     Orientation::matrixTranspose(m3); 
     glMultMatrixf(m3); 
     if (i_reflectionOn) glMultMatrixf(Orientation::matrixGet3x3(i_reflectionTransform)); 
     renderMesh(*skyBox,NULL,1); 
     glPopMatrix(); 
     glDisable(GL_TEXTURE_2D); 
     if (clrmask&GLE_CLR_DEPTH) glClear(GL_DEPTH_BUFFER_BIT); 
     else glDepthMask(1); 
     glAble(GL_DEPTH_TEST,depthmode!=GLE_ALWAYS); 
     break; 
    } 
    // Camera 
    glMultMatrixf(cam.getAbsInverseMatrix()); 
    if (i_reflectionOn) glMultMatrixf(i_reflectionTransform); 
    // Lighting 
    i_lightOn = uselight; 
    glAble(GL_LIGHTING,i_lightOn); 
} 
+0

您可以使用[Mesa](http://www.mesa3d.org/)軟件光柵器進行重現嗎? – genpfault

+2

什麼顯卡?除NVidia之外的任何人的windows openGL驅動程序都非常糟糕 - 英特爾驅動程序是最糟糕的。 –

+0

看起來像一個bug給我。將您的GL驅動程序更新到硬件的最新版本,如果它仍然重現,請提交錯誤... – Bahbar

回答

0

這看起來像一個驅動程序的bug給我。但是,有兩種情況實際上可能是代碼中的錯誤。

首先,當調用glDisable()時,您可能會處於glBegin()/ glEnd()塊的中間,導致一些錯誤並且還會結束該塊,從而有效地使第二次調用glDisable()合法且有效。請注意,這是一個愚蠢的例子與glBegin()/ glEnd(),它可能幾乎任何情況下的OpenGL錯誤被捕獲。確保在整個代碼中插入glGetError()調用。我的猜測是第一次調用glDisable()會生成GL_INVALID_OPERATION。

其次,你不是剪刀測試,但你仍然使用相同的值調用glViewport()。這會在NVIDIA上產生相反的效果(不是剪輯glClear()和剪貼畫),但很可能它在其他驅動程序/ GL實現方面做得相反。