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+ 失败的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL 3.3 两个 GPU 上的两个不同结果 nVidia Optimus 与阴影映射
iPad/X 平台上的 OpenGL ES 应用程序:C++ 还是 Objective-C?