C++ OpenGL glGetUniformBlockIndex在nvidea GPU上返回无效的索引';s

C++ OpenGL glGetUniformBlockIndex在nvidea GPU上返回无效的索引';s,c++,opengl,gpu,rendering,C++,Opengl,Gpu,Rendering,我已经在这个opengl游戏引擎上工作了很长一段时间了,我正在用程序生成的行星在其中制作一个游戏。然而,我有一些奇怪的问题,我已经坚持了三个星期了 为了动态生成行星,我使用了一种由镶嵌和几何体着色器组成的材质来进行生成。这样,它的速度非常快。现在在细分评估着色器中,我使用统一缓冲块将行星生成的参数发送到gpu(我认为是48字节x噪波层数) 现在所有这些都可以在我的台式电脑上正常工作,它有radeon r9 390,也可以在我的笔记本电脑上工作,它有gtx 1060。但是,在下面的桌面gpu上,调

我已经在这个opengl游戏引擎上工作了很长一段时间了,我正在用程序生成的行星在其中制作一个游戏。然而,我有一些奇怪的问题,我已经坚持了三个星期了

为了动态生成行星,我使用了一种由镶嵌和几何体着色器组成的材质来进行生成。这样,它的速度非常快。现在在细分评估着色器中,我使用统一缓冲块将行星生成的参数发送到gpu(我认为是48字节x噪波层数)

现在所有这些都可以在我的台式电脑上正常工作,它有radeon r9 390,也可以在我的笔记本电脑上工作,它有gtx 1060。但是,在下面的桌面gpu上,调用glGetUniformBlockIndex时,我得到了一个无效的_索引,显然它无法工作,因为它试图使用错误的参数生成。 -gtx 1050 -GTX1060 -gtx 960 -gtx 970 -rtx 2080

在以下gpu上,一切正常,没有错误: -radeon r9 390 -rx 580 -高清7770

我没有任何其他GPU可供我进一步测试

现在,在做了一些研究之后,我知道统一缓冲块的大小以及可以拥有的组件的数量和数量是有限制的。但是,考虑到我将最大层数降到1并再次测试,问题仍然存在。这也不可能是内存不足的问题,因为HD7770只有1GB的vram,而1060只有4-6GB的vram,而且这种情况仍然发生在1060上

我发现的另一件事是,当变量对输出没有贡献时,驱动程序可以优化着色器变量,正如您可以从着色器代码中看到的那样,它对输出的贡献是有限的

所以,在一些代码上

在material类中有一个CreateUniformBuffer函数,该函数获取统一缓冲区块的索引,并将其绑定到允许编辑它的缓冲区。请注意,程序在获取无效的_索引后已经崩溃,因此获取索引必须是问题所在

GLuint Material::CreateUniformBuffer(const std::string& name, GLuint bufferSize)
{
    GLuint uniformBlockIndex = glGetUniformBlockIndex(m_pShader->m_ShaderProgramID, name.data());
    Utilities::Debug::LogGLError(glGetError());
    if (uniformBlockIndex == GL_INVALID_INDEX)
    {
        Utilities::Debug::LogError("Material::CreateUniformBuffer > Uniform buffer block with name " + name + " not found!");
        return 0;
    }

    Utilities::Debug::LogGLError(glGetError());
    glUniformBlockBinding(m_pShader->m_ShaderProgramID, uniformBlockIndex, m_BufferBindIndex);
    Utilities::Debug::LogGLError(glGetError());

    // Uniform buffer object for lights
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    Utilities::Debug::LogGLError(glGetError());
    glBindBuffer(GL_UNIFORM_BUFFER, bufferID);
    Utilities::Debug::LogGLError(glGetError());
    glBufferData(GL_UNIFORM_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW);
    Utilities::Debug::LogGLError(glGetError());
    glBindBufferBase(GL_UNIFORM_BUFFER, uniformBlockIndex, bufferID);
    Utilities::Debug::LogGLError(glGetError());
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    Utilities::Debug::LogGLError(glGetError());

    m_UniformBufferObjects.push_back(bufferID);

    ++m_BufferBindIndex;
    return bufferID;
}
这是细分求值着色器,请注意顶部有一条#include“SimplexNoise”线,但在opengl中不起作用,引擎为着色器提供了一个预编译阶段,在该阶段中,它将读取着色器代码,并用编译着色器之前包含的文件内容替换任何#include指令

行星着色器

#version 450

#include "SimplexNoise.shader"

layout(triangles, equal_spacing, cw) in;
in vec3 tcPosition[];
out vec3 tePosition;
out float teElevation;

uniform int NumNoiseLayers;

struct NoiseLayer
{
    float Strength;
    float BaseRoughness;
    float Roughness;
    float Persistance;

    vec3 Center;
    float MinValue;

    int NumLayers;
    int UseFirstLayerAsMask;
    int NoiseFilterType;
    float Weight;
};

const int MaxNoiseLayers = 4;
layout(std140) uniform NoiseBlock
{
    NoiseLayer NoiseLayers[MaxNoiseLayers];
} _NoiseData;

float Evaluate(vec3 p, int layer)
{
    int filterType = _NoiseData.NoiseLayers[layer].NoiseFilterType;
    if (filterType == 0)
        return SimpleEvaluate(p, int(_NoiseData.NoiseLayers[layer].NumLayers), _NoiseData.NoiseLayers[layer].BaseRoughness, _NoiseData.NoiseLayers[layer].Roughness, _NoiseData.NoiseLayers[layer].Persistance, _NoiseData.NoiseLayers[layer].Center, _NoiseData.NoiseLayers[layer].MinValue, _NoiseData.NoiseLayers[layer].Strength);

    return RigidEvaluate(p, int(_NoiseData.NoiseLayers[layer].NumLayers), _NoiseData.NoiseLayers[layer].BaseRoughness, _NoiseData.NoiseLayers[layer].Roughness, _NoiseData.NoiseLayers[layer].Persistance, _NoiseData.NoiseLayers[layer].Center, _NoiseData.NoiseLayers[layer].MinValue, _NoiseData.NoiseLayers[layer].Strength, _NoiseData.NoiseLayers[layer].Weight);
}

float CalculateTotalStrength()
{
    float strength = 0.0;
    for (int i = 0; i < NumNoiseLayers; i++)
    {
        strength += _NoiseData.NoiseLayers[i].Strength;
    }
    return strength;
}

float LayeredEvaluate(vec3 p)
{
    float firstLayerValue = 0.0;
    float elevationAverage = 0.0;

    float totalStrength = CalculateTotalStrength();

    float unscaledElevation = 0.0;
    float scaledElevation = 0.0;

    float noiseValue = 0.0;
    float strengthPercentage = 0.0;
    if (NumNoiseLayers > 0)
    {
        unscaledElevation = Evaluate(p, 0);
        scaledElevation = max(0.0, unscaledElevation);
        noiseValue = scaledElevation;
        elevationAverage = unscaledElevation;
        firstLayerValue = noiseValue;
    }

    for (int i = 1; i < NumNoiseLayers; i++)
    {
        float mask = (_NoiseData.NoiseLayers[i].UseFirstLayerAsMask == 1) ? firstLayerValue : 1.0;
        unscaledElevation = Evaluate(p, 0);
        scaledElevation = max(0.0, unscaledElevation);
        elevationAverage += unscaledElevation;

        noiseValue += scaledElevation;
    }

    elevationAverage /= totalStrength;

    teElevation = clamp(elevationAverage * 115.0, -0.99, 0.99);

    return noiseValue;
}

void main()
{
    vec3 p0 = gl_TessCoord.x * tcPosition[0];
    vec3 p1 = gl_TessCoord.y * tcPosition[1];
    vec3 p2 = gl_TessCoord.z * tcPosition[2];
    tePosition = normalize(p0 + p1 + p2);
    float hieght = LayeredEvaluate(tePosition);
    gl_Position = vec4(tePosition * (1.0 + hieght), 1);
}
设置SSBO数据的代码

void Material::WriteToShaderStorageBuffer(GLuint ssboID, const void* data, GLsizeiptr size)
{
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboID);
    Utilities::Debug::LogGLError(glGetError());
    GLvoid* bufferData = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
    Utilities::Debug::LogGLError(glGetError());
    memcpy(bufferData, data, size);
    glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    Utilities::Debug::LogGLError(glGetError());
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, NULL);
    Utilities::Debug::LogGLError(glGetError());
}
着色器中的更改,以将均匀块转化为SSBO

const int MaxNoiseLayers = 4;
layout(std430, binding = 0) buffer NoiseBlock
{
    NoiseLayer NoiseLayers[MaxNoiseLayers];
} _NoiseData;

我发现问题是由SimplexNoise着色器文件中的int array buffer _random[512]引起的,我不确定为什么这只会在nvidea gpu上引起问题,但我假设是nvidea gpu上超出了某种限制,导致整个着色器在没有任何警告或错误的情况下损坏


我通过将此数组转换为另一个UBO并将其绑定到索引1来修复它。

我发现问题是由SimplexNoise着色器文件中的int array buffer\u random[512]引起的,我不知道为什么这只会在nvidea gpu上引起问题,但我假设这是nvidea gpu上超出了某种限制,导致整个着色器在没有任何警告或错误的情况下中断


我通过将此数组转换为另一个UBO并将其绑定到索引1来修复它。

如果这是统一块大小的问题,请改用一个。@rabbi76我刚刚实现了这些,但我注意到这对性能有很大影响,经过一段时间的实验,我发现使用GL_DYNAMIC_DRAW作为缓冲区使用会产生最好的效果,但是我似乎仍然比使用统一缓冲区时少50-100 fps,当数据发生变化时,只向缓冲区写入数据的小优化会有很大帮助,但我仍然注意到,与统一缓冲区相比,速度要低20-50 fps,我不确定我是否能活下去,而且我不认为4 x 48字节对于统一缓冲区来说太大?SSBO没有解决问题,它消除了崩溃(可能是因为我没有搜索块索引)但是在所有的桌面nvidea gpu上,它似乎不再渲染一个行星,而在我的PC上(使用amd gpu)它似乎渲染了预期的渲染效果。如果是统一块的大小问题,那么就用一个来代替。@rabbi76我刚刚实现了这些功能,但我注意到这对性能有很大的影响,经过一点实验后,我发现使用GL_DYNAMIC_DRAW作为缓冲区使用会产生最好的效果,但我仍然使用它em比使用统一缓冲区的速度要低50-100 fps,这是一个很小的优化,只在数据更改时写入缓冲区会有很大帮助,但我仍然注意到比使用统一缓冲区的速度要低20-50 fps,我不确定我是否能活下去,而且我不认为4 x 48字节对于统一缓冲区来说太大?SSBO没有解决了这个问题,它摆脱了崩溃(可能是因为我没有搜索块索引),但在所有桌面nvidea gpu上,它似乎不再渲染单个行星,而在我的PC上(使用amd gpu),它似乎渲染了预期渲染的内容
void Material::WriteToShaderStorageBuffer(GLuint ssboID, const void* data, GLsizeiptr size)
{
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboID);
    Utilities::Debug::LogGLError(glGetError());
    GLvoid* bufferData = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
    Utilities::Debug::LogGLError(glGetError());
    memcpy(bufferData, data, size);
    glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
    Utilities::Debug::LogGLError(glGetError());
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, NULL);
    Utilities::Debug::LogGLError(glGetError());
}
const int MaxNoiseLayers = 4;
layout(std430, binding = 0) buffer NoiseBlock
{
    NoiseLayer NoiseLayers[MaxNoiseLayers];
} _NoiseData;