Intel/AMD C++ 上的 OpenGL 3+ 失败

Posted

技术标签:

【中文标题】Intel/AMD C++ 上的 OpenGL 3+ 失败【英文标题】:OpenGL 3+ failure on Intel/AMD C++ 【发布时间】:2015-11-22 07:54:52 【问题描述】:

我正在为旧游戏引擎开发更新的渲染器,但我在 Intel 和 AMD 卡上遇到了非常令人沮丧的视觉问题。好的,我发现了大量关于英特尔和 OpenGL 问题的页面,但我希望它至少也可以在 AMD 上的 NVidia 卡上运行,无论哪一代,它似乎都可以完美运行。 我正在从项目中删除一些代码,所以请告诉我是否缺少某些东西。 起初我认为它是由旧的 GL 固定管道残余物引起的,但在清理之后问题仍然存在。这是它的样子:

我一直在研究https://www.opengl.org/wiki/Debugging_Tools 上列出的调试器和调试方法,我逐行使用了经典的 glGetError,我使用了 AMD 的 CodeXL 和 GPUProfiler。尽管其中一些工具相当复杂,而且我对所有东西都不熟悉 - 这些东西都没有显示警告或错误。

好的,输入一些信息:上下文创建目前看起来像这样:

PIXELFORMATDESCRIPTOR pfd =

    sizeof(PIXELFORMATDESCRIPTOR),
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
    PFD_TYPE_RGBA,
    DesiredColorBits,
    0, 0, 0, 0, 0, 0,
    0, 0,
    0, 0, 0, 0, 0,
    DesiredDepthBits,
    DesiredStencilBits,
    0,
    PFD_MAIN_PLANE,
    0,
    0, 0, 0
;

INT nPixelFormat = ChoosePixelFormat( hDC, &pfd );
check(nPixelFormat);
verify(SetPixelFormat( hDC, nPixelFormat, &pfd ));

// oldstyle context to init glew.
HGLRC tempContext = wglCreateContext(hDC);
wglMakeCurrent(hDC, tempContext);

//init glew
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
    appErrorf(TEXT("Error: Init glew failed: %s"), appFromAnsi((char*)glewGetErrorString(err)));
else debugf(NAME_Init, TEXT("Glew successfully initialized."));

//Now init pure OpenGL >= 3.3 context.
if (WGLEW_ARB_create_context && WGLEW_ARB_pixel_format)

    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(tempContext);

    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = DesiredColorBits;
    pfd.cDepthBits = DesiredDepthBits;
    pfd.iLayerType = PFD_MAIN_PLANE;

    const INT iPixelFormatAttribList[] =
    
        WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
        WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
        WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
        WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
        WGL_COLOR_BITS_ARB, DesiredColorBits,
        WGL_DEPTH_BITS_ARB, DesiredDepthBits,
        WGL_STENCIL_BITS_ARB, DesiredStencilBits,
        0 // End of attributes list
    ;

    INT ContextFlags=0;
    if (UseOpenGLDebug)
         ContextFlags = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB;
    else ContextFlags = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;

    INT iContextAttribs[] =
    
        WGL_CONTEXT_MAJOR_VERSION_ARB, MajorVersion,
        WGL_CONTEXT_MINOR_VERSION_ARB, MinorVersion,
        WGL_CONTEXT_FLAGS_ARB, ContextFlags,
        0 // End of attributes list
    ;

    INT iPixelFormat, iNumFormats;
    wglChoosePixelFormatARB(hDC, iPixelFormatAttribList, NULL, 1, &iPixelFormat, (UINT*)&iNumFormats);

    // pfd oldstyle crap...
    debugf(NAME_Init, TEXT("DesiredColorBits: %i"), DesiredColorBits);
    debugf(NAME_Init, TEXT("DesiredDepthBits: %i"), DesiredDepthBits);
    debugf(NAME_Init, TEXT("DesiredStencilBits: %i"), DesiredStencilBits);
    debugf(NAME_Init, TEXT("PixelFormat: %i"), iPixelFormat);
    if (!SetPixelFormat(hDC, iPixelFormat, &pfd))
    
        appErrorf(TEXT("Error: SetPixelFormat failed."));
        return;
    

    hRC = wglCreateContextAttribsARB(hDC, 0, iContextAttribs);

else  appErrorf(TEXT("Error: Init glew failed: %s"), appFromAnsi((char*)glewGetErrorString(err)));

if(hRC)

    MakeCurrent();

    debugf(NAME_Init, TEXT("GL_VENDOR     : %s"), appFromAnsi((const ANSICHAR *)glGetString(GL_VENDOR)));
    debugf(NAME_Init, TEXT("GL_RENDERER   : %s"), appFromAnsi((const ANSICHAR *)glGetString(GL_RENDERER)));
    debugf(NAME_Init, TEXT("GL_VERSION    : %s"), appFromAnsi((const ANSICHAR *)glGetString(GL_VERSION)));
    debugf(NAME_Init, TEXT("GLEW Version  : %s"), appFromAnsi((const ANSICHAR *)glewGetString(GLEW_VERSION)));

    int NumberOfExtensions=0;
    glGetIntegerv(GL_NUM_EXTENSIONS, &NumberOfExtensions);
    for (INT i = 0; i<NumberOfExtensions; i++)
    
        FString ExtensionString = appFromAnsi((const ANSICHAR *)glGetStringi(GL_EXTENSIONS, i));
        debugf(NAME_DevLoad, TEXT("GL_EXTENSIONS(%i) : %s"), i, ExtensionString);
    
    debugf(NAME_Init, TEXT("OpenGL %i.%i context initialized!"), MajorVersion,MinorVersion);

else
    appErrorf(TEXT("Error: No OpenGL %i.%i context support."), MajorVersion, MinorVersion);

if( ShareLists && AllContexts.Num() )
    verify(wglShareLists(AllContexts(0),hRC)==1);
AllContexts.AddItem(hRC);

if (UseOpenGLDebug)


    glDebugMessageCallbackARB(&UXOpenGLRenderDevice::DebugCallback, NULL);
    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
    GWarn->Logf(TEXT("OpenGL debugging enabled, this can cause severe performance drain!"));

我尝试了几种方法,最后得到了 glew。然而,我也尝试了更简单的版本,只是使用了 initing glew,还尝试了其他东西,使用了高兴和 SDL2 来创建上下文。结果总是一样的。

矩阵是这样设置的:

viewMat = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f, -1.0f, -1.0f));
modelMat = glm::mat4(1.0f);
projMat = glm::frustum(-RProjZ*zNear, +RProjZ*zNear, -Aspect*RProjZ*zNear, +Aspect*RProjZ*zNear, 1.0f*zNear, zFar);

这里是绘图例程之一,有更复杂的功能,但是这个非常简单的已经发生了:

顶点着色器

#version 330
layout (location = 0) in vec3 v_coord;      // == gl_Vertex
layout (location = 2) in vec2 TexCoords;

layout(std140) uniform GlobalMatrices

    mat4 modelviewprojMat;
;

uniform vec4 DrawColor;
out vec4 vDrawColor;
out vec2 vTexCoords;

void main(void)

    vTexCoords=TexCoords;
    vDrawColor=DrawColor;

    gl_Position = modelviewprojMat * vec4(v_coord, 1.0);

片段着色器

#version 330
uniform sampler2D Texture0;
uniform float AlphaThreshold;

in vec4 vDrawColor;
in vec2 vTexCoords;

out vec4 FragColor;

void main(void)

    vec4 Color = texture(Texture0, vTexCoords); 

    if(Color.a <= AlphaThreshold) 
        discard;

    FragColor = Color*vDrawColor; 

在这里我还尝试了各种版本,从 150 到 430、核心、兼容性,甚至快速跳转到 OpenGL ES。

这里是对应的C++函数

DrawTileVerts(FLOAT* verts, UINT size, FLOAT* tex, UINT texsize, FPlane Color)

    CHECK_GL_ERROR();
    glBindVertexArray(DrawTileVertsVao);
    // Verts
    glBindBuffer(GL_ARRAY_BUFFER, DrawTileVertBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(VERTEX_COORD_ATTRIB);
    glVertexAttribPointer(VERTEX_COORD_ATTRIB, 3, GL_FLOAT, GL_FALSE, sizeof(float) * FloatsPerVertex, 0);

    // Textures
    glBindBuffer(GL_ARRAY_BUFFER, DrawTileTexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * texsize, tex, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(TEXTURE_COORD_ATTRIB);
    glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, sizeof(float) * TexCoords2D, 0);

    glUniform4f(DrawTile_DrawColor, Color.X, Color.Y, Color.Z, Color.W);

    glDrawArrays(GL_TRIANGLE_FAN, 0, size);

    // Clean up
    glDisableVertexAttribArray(VERTEX_COORD_ATTRIB);
    glDisableVertexAttribArray(TEXTURE_COORD_ATTRIB);
    CHECK_GL_ERROR();
    glBindVertexArray(0);

我非常感谢任何提示我可以尝试什么,如何获取更多信息或我可以尝试什么。另外,如果您需要更多代码,请告诉我,因为这还缺少一些部分。我暂时忽略了纹理,但我很确定这不相关。在着色器中没有 AlphaThreshold 时也会发生这种情况,这是我稍后添加的。

【问题讨论】:

尝试使用像 renderdoc 或 AMD 的 GPUPerf 这样的帧调试器 - 它们允许您导航整个渲染过程 drawcall-to-drawcall 并随时查看帧缓冲区、纹理等的内容。它们还会向您显示当前绑定的网格,因此您可以查看问题是在上传的顶点缓冲区内还是其他地方。 我已经试过了,但没有成功,但我仍然需要学习很多东西,而且这个功能现在是一个非常简单的绘制瓷砖,甚至不是一个复杂的网格,所以我假设它成为一些更“全球”的问题 【参考方案1】:

在您的 DrawTileVerts 中,您传入了一个名为“size”的参数。

从您将其传递给 glDrawArrays 调用的方式来看,它看起来应该是顶点数。

但是从您使用它来计算传递给 glBufferData 的大小的方式来看,您将其视为浮点数。

我认为您对 glBufferData 的调用应该是

glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size * FloatsPerVertex, verts, GL_DYNAMIC_DRAW);

或者您对 glDrawArrays 的调用应该是:

glDrawArrays(GL_TRIANGLE_FAN, 0, size / FloatsPerVertex);

有足够的信息可以看出存在不一致之处,但没有足够的信息来确定哪个是正确的解决方案。

我还会仔细检查您使用 texsize 的方式,因为这也可能是错误的,但没有看到更多代码,我无法判断。

【讨论】:

天啊!我检查了这部分就像 1000000 次没有看到它。我可以亲吻你的脚。事实上,我错过了“/FloatsPerVertex”——有趣的是,NVidia 似乎对这样的错误更加宽容。我希望这篇文章能帮助其他人发现这样的问题。

以上是关于Intel/AMD C++ 上的 OpenGL 3+ 失败的主要内容,如果未能解决你的问题,请参考以下文章

AMD系列CPU

OpenGL 3.3 两个 GPU 上的两个不同结果 nVidia Optimus 与阴影映射

iPad/X 平台上的 OpenGL ES 应用程序:C++ 还是 Objective-C?

C++ openGl 纹理将图像映射到球体上

如何为我的 GIF tilesheet 制作动画(OpenGL、DevIL、C++)

C++ 和 OpenGL 帮助 [关闭]