nVidia和ATI的OpenGL渲染有何不同?

4

最近我更新了ATI驱动程序(我使用的是HD7970)到最新版本,我的一些OpenGL项目对象停止工作了。更重要的是,它们在nVidia最新的驱动程序上工作正常(在960m上测试)。ATI和nVidia渲染管道之间有什么区别,我应该知道吗?

附加信息:

  • 没有glGetError()的错误,
  • 着色器编译和链接正确,
  • 其他渲染对象工作正常,但VBO填充和绘制命令不同。工作正常的是从*.obj文件加载并通过glDrawArrays()绘制的。破损的 VBO 是由多边形化器(计算着色器)填充的,它从用于存储的image2D中获取顶点,并通过glDrawElements()绘制,
  • 使用我的最简单的 GPU 调试器检查了顶点和片段着色器是否启动。

当我尝试使用三角形进行绘制时,我看不到任何东西,但是当我切换到GL_POINTS时,我看到绿点(来自片段着色器的输出是纯绿色通道),它们按照预期移动。这可能表明顶点着色器正在启动,因为MVP乘法正在发生。

这些是具有一个大VBO的行星LOD对象,因此我使用一个函数绑定所有缓冲区,另一个函数绘制必要的高度图。VBO大小为128MB

初始化:

glGenBuffers(1, &VBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, VBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, size * sizeof(vec4), NULL, GL_DYNAMIC_COPY);

glGenBuffers(1, &IndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize * sizeof(unsigned int), NULL, GL_DYNAMIC_DRAW);

glGenBuffers(1, &Normals);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, Normals);
glBufferData(GL_SHADER_STORAGE_BUFFER, size * sizeof(vec4), NULL, GL_DYNAMIC_COPY);

通过多边形化程序(计算着色器)填充VBO:

    #version 430 core
layout( std430, binding=1 ) buffer ParamsBuffer
  {
    float size;
        uint index;
        int parentIndex;
        uint textureSize;
        vec4 upVector;
        vec4 Position;
        vec4 quadrant;
  };
  layout( std430, binding=2 ) buffer VertBuffer
  {
    vec4 VBO[ ]; 
  };

  layout( std430, binding=3 ) buffer NormalsBuffer
  {
    vec4 Normals[ ]; 
  };

 layout(std430, binding = 4) buffer IndexBuffer
{
 uint Index[];
};

  layout( std430, binding=10 ) buffer DebugBuffer
    {
      vec4 debug; 
    };
  layout (rgba32f)  uniform image2D HeightMap;
  layout (rgba32f)  uniform image2D NormalMap;
  layout( local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

  void main(void)
  {
    uint  WGidY=(gl_WorkGroupID.y);
    uint  WGidX=(gl_WorkGroupID.x);
    uint mapVBOOffset=index*textureSize*textureSize;
    uint indexOffset=6*index*textureSize*textureSize;
        VBO[WGidY*textureSize+WGidX+mapVBOOffset]=imageLoad(HeightMap, ivec2(WGidX, WGidY));
    Normals[WGidY*textureSize+WGidX+mapVBOOffset]=imageLoad(NormalMap, ivec2(WGidX, WGidY));
   // debug=VBO[0];
    if(WGidX==textureSize-1 || WGidY==textureSize-1)
    return;

    uint localIndex = 6*(WGidY*textureSize+WGidX)+indexOffset;
    Index[localIndex+0]=(WGidY+1)*textureSize+WGidX  +mapVBOOffset;
    Index[localIndex+1]=WGidY*textureSize    +WGidX+1+mapVBOOffset;
    Index[localIndex+2]=WGidY*textureSize    +WGidX  +mapVBOOffset;
    Index[localIndex+3]=WGidY*textureSize    +WGidX+1+mapVBOOffset;
    Index[localIndex+4]=(WGidY+1)*textureSize+WGidX  +mapVBOOffset;
    Index[localIndex+5]=(WGidY+1)*textureSize+WGidX+1+mapVBOOffset;

  }

绑定:

    glUseProgram(RenderProgram);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, PerFrameBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, ConstantBuffer);

glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, Normals);
glVertexAttribPointer(
    2,                  
    4,                  
    GL_FLOAT,           
    GL_FALSE,           
    0,                  
    (void*)0            
);


glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(
    0,                  
    4,                  
    GL_FLOAT,           
    GL_FALSE,           
    0,                 
    (void*)0            
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);

绘图:

float discardFactor = 0;
GLint drawMode;
if(renderMode==0)
 drawMode = GL_TRIANGLES;
if (renderMode == 1)
{
    drawMode = GL_PATCHES;
    GLint vert= 3;
    glPatchParameteri(GL_PATCH_VERTICES, 3);
}
if (tile->quadrant_x == nullptr)
{
        HeightMap hp = tile->quadrantX;
        if (CornersInFrustum(hp.Corners))
        {
            int mapOffset = tile->quadrantX.index * 6 * heightMapSize*heightMapSize * sizeof(unsigned int);
            glDrawElements(drawMode, 6 * heightMapSize*heightMapSize, GL_UNSIGNED_INT, (void*)mapOffset);
        }

}

if (tile->quadrant_y == nullptr)
{
    HeightMap hp = tile->quadrantY;
    if ( CornersInFrustum(hp.Corners))
    {
        int mapOffset = tile->quadrantY.index * 6 * heightMapSize*heightMapSize * sizeof(unsigned int);
        glDrawElements(drawMode, 6 * heightMapSize*heightMapSize, GL_UNSIGNED_INT, (void*)mapOffset);


    }
}

if (tile->quadrant_z == nullptr)
{
    HeightMap hp = tile->quadrantZ;
    if (CornersInFrustum(hp.Corners))
    {
        int mapOffset = tile->quadrantZ.index * 6 * heightMapSize*heightMapSize * sizeof(unsigned int);
        glDrawElements(drawMode, 6 * heightMapSize*heightMapSize, GL_UNSIGNED_INT, (void*)mapOffset);
    }


}

if (tile->quadrant_w == nullptr)
{
    HeightMap hp = tile->quadrantW;
    if (CornersInFrustum(hp.Corners))
    {
        int mapOffset = tile->quadrantW.index * 6 * heightMapSize*heightMapSize * sizeof(unsigned int);
        glDrawElements(drawMode, 6 * heightMapSize*heightMapSize, GL_UNSIGNED_INT, (void*)mapOffset);
    }


}

顶点着色器:

#version 430 //core
layout(location = 0) in vec4 vertexPosition_modelspace;
layout(location = 2) in vec4 vertexNormal_modelspace;

layout(std430, binding = 4) buffer PerFrame
{
    mat4 ViewMatrix;
    vec4 CameraPosition;
    vec4 CameraForward;
    mat4 ModelMatrix;
    float time;
    float perFrametab[3];
};

layout(std430, binding = 5) buffer Constant
{
    mat4 ProjectionMatrix;
    vec4 SeedBuffer;
    vec2 screenSize;
};
layout( std430, binding=10 ) buffer DebugBuffer
{
    vec4 debug; 
};


out vec3 Position_worldspace;
out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;
out vec3 LightDirection_cameraspace;
out vec3 LightPosition_worldspace;
out vec3 NormalWorldSpace;

void main()
{
gl_Position =ProjectionMatrix*
ViewMatrix*ModelMatrix*
vec4(vertexPosition_modelspace.xyz,1);

float C = 1,
near = 0.1,
far = 10000000.0f;
gl_Position.z = (2*log2(C*gl_Position.w + 1) / log2(C*far + 1) - 1) * gl_Position.w;
Position_worldspace = (ModelMatrix*vec4(vertexPosition_modelspace.xyz,1)).xyz;
Normal_cameraspace = ( ViewMatrix *(vec4(vertexNormal_modelspace.xyz,0))).xyz; 
vec4 normalTemp=ModelMatrix*vertexNormal_modelspace;
NormalWorldSpace=normalize(normalTemp.xyz);
}

如果你减小VBO的大小,它能正常工作吗? - Ripi2
减小VBO大小仍然没有帮助。@Jesper Juhl现在我只是在玩RenderDoc,稍后会尝试你的建议。 - Kedriik
我已经进行了一些调试,发现可能是计算着色器中的imageStore / imageLoad出了问题,因为当我想要从image2D中加载某些内容时,它总是vec4(0,0,0,0)。你们有没有看到我的images2D +计算着色器有什么问题? - Kedriik
@Spektre 谢谢,我会尝试搜索 CPU 内存泄漏。我的行星半径为 2 个单位,并且有一些细节层次,它们并不是特别大,所以我不认为这是问题的原因,但还是谢谢你提供的线索。昨天我在搜索时发现,在计算着色器中无法加载或写入 image2D(当我检索随机 VBO 位置时,我始终获得零值,因此看起来每个顶点都位于 0,0,0 的位置。我不知道,也许计算着色器和 ATI 有什么问题? - Kedriik
你自己回答中提到的代码不在问题中。 - Andreas
显示剩余3条评论
1个回答

1

好的,我找到了一个解决方案。问题出在计算着色器中的imageStore()和imageLoad()函数。即使我用image2D作为存储目的,我仍需要添加

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

生成纹理后,这就是ATI和Nvidia之间的差异。

啊,我认识这个。一些驱动默认使用mipmaps,因此在纹理加载后没有GenerateMipmaps或最近过滤纹理将不起作用。你介意测试GenerateMipmaps并查看是否可以省略过滤修复吗? - Andreas
1
glGenerateMipmap() 使我的纹理存储也能正常工作。 - Kedriik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接