产生 intel_drm 个错误的动画

Animations producing intel_drm errors

我正在使用 Assimp 在我的模型加载器中实现动画;用于渲染的 C++/OpenGL。我一直在广泛关注本教程:http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html。可以说我没有完全按照教程进行操作,因为有些地方我不同意代码方面的观点,所以我对其进行了调整。请注意,我没有使用作者那里使用的 none 数学组件,所以我使用了 glm。无论如何,问题是有时我的程序 运行s,而在其他时候则没有。当我 运行 我的程序时,它会 运行 然后立即崩溃,而在其他时候它会像往常一样简单地 运行 。

需要考虑的几件事:

  1. 在添加 animations/loading 骨骼之前,模型加载器工作完全正常并且加载模型时没有导致任何崩溃;

  2. 没有骨骼的模型仍然可以正常加载;只有在加载带有骨骼的模型时才会出现问题。

  3. 请注意,没有渲染骨骼中的任何内容。我什至还没有开始将骨骼分配给顶点属性;甚至连着色器都没有为此修改。

  4. 一切都在一个线程上 运行;还没有多线程...

所以,我很自然地接受了这段实际加载骨骼的代码。我已经调试了应用程序,发现问题主要出在这里:

Mesh* processMesh(uint meshIndex, aiMesh *mesh)
{
    vector<VertexBoneData> bones;

    bones.resize(mesh->mNumVertices);

    // .. getting other mesh data

    if (pAnimate)
    {
        for (uint i = 0; i < mesh->mNumBones; i++)
        {
            uint boneIndex = 0;
            string boneName(mesh->mBones[i]->mName.data);
            auto it = pBoneMap.find(boneName);

            if (it == pBoneMap.end())
            {
                boneIndex = pNumBones;
                ++pNumBones;
                BoneInfo bi;
                pBoneInfo.push_back(bi);
                auto tempMat = mesh->mBones[i]->mOffsetMatrix;
                pBoneInfo[boneIndex].boneOffset = to_glm_mat4(tempMat);
                pBoneMap[boneName] = boneIndex;
            }
            else boneIndex = pBoneMap[boneName];

            for (uint j = 0; j < mesh->mBones[i]->mNumWeights; j++)
            {
                uint vertexID = mesh->mBones[i]->mWeights[j].mVertexId;
                float weit = mesh->mBones[i]->mWeights[j].mWeight;
                bones.at(vertexID).addBoneData(boneIndex, weit);
            }
        }
    }
}

在最后一行中,作者使用了 [] 运算符来访问元素,但我决定使用 '.at 进行范围检查。函数 to_glm_mat4 是这样定义的:

glm::mat4 to_glm_mat4(const aiMatrix4x4 &m)
{
    glm::mat4 to;

    to[0][0] = m.a1; to[1][0] = m.a2;
    to[2][0] = m.a3; to[3][0] = m.a4;
    to[0][1] = m.b1; to[1][1] = m.b2;
    to[2][1] = m.b3; to[3][1] = m.b4;
    to[0][2] = m.c1; to[1][2] = m.c2;
    to[2][2] = m.c3; to[3][2] = m.c4;
    to[0][3] = m.d1; to[1][3] = m.d2;
    to[2][3] = m.d3; to[3][3] = m.d4;

    return to;
}

我还必须更改 VertexBoneData,因为它使用了我认为有缺陷的原始数组:

构造 VertexBoneData { 矢量骨骼ID; 矢量权重;

VertexBoneData()
{
    reset();

    boneIDs.resize(NUM_BONES_PER_VERTEX);
    weights.resize(NUM_BONES_PER_VERTEX);
}

void reset()
{
    boneIDs.clear();
    weights.clear();
}

void addBoneData(unsigned int boneID, float weight)
{
    for (uint i = 0; i < boneIDs.size(); i++)
    {
        if (weights.at(i) == 0.0) // SEG FAULT HERE
        {
            boneIDs.at(i) = boneID;
            weights.at(i) = weight;
            return;
        }
    }
    assert(0);
}

};

现在,我不完全确定是什么导致了崩溃,但最让我困惑的是有时程序 运行s(暗示代码不一定是罪魁祸首)。所以我决定做一个 debug-smashdown,其中涉及我检查每根骨头(我跳过了一些;有很多骨头!)并发现在加载所有骨头后我会得到这个非常奇怪的错误:

No source available for "drm_intel_bo_unreference() at 0x7fffec369ed9"

有时我会得到这个错误:

Error in '/home/.../: corrupted double-linked list (not small): 0x00000 etc ***

有时我会从 glm 得到一个关于 vec4 实例化的段错误;

有时...我的程序 运行 从未崩溃过!

公平地说,在我的笔记本电脑上实现动画可能有点苛刻,所以这可能是一个 CPU/GPU 问题,因为它无法在一个 gulp 中处理如此多的数据,这导致这次崩溃。我的理论是,由于它无法处理那么多数据,因此数据永远不会分配给向量。

我没有使用任何多线程,但我已经想到了。我认为可能是 CPU 无法处理如此多的数据,因此有机会 运行。如果我实现了线程,那么骨骼加载是在另一个线程上完成的;或者更好,使用互斥锁,因为我发现通过缓慢调试应用程序 运行s,这是有道理的,因为每个任务都被分解成块;这就是互斥量本身在技术上所做的。

为了论证,我的技术规格:

Ubuntu 15.04 64-bit
Intel i5 dual-core
Intel HD 5500
Mesa 10.5.9 (OpenGL 3.3)
Programming on Eclipse Mars

我想问一下,到底是什么导致了这些 intel_drm 错误?

我复现了这个问题,发现可能是加载骨骼时缺少多线程的问题。我决定按照上述教程中的规定将加载骨骼勘误表移动到它自己的函数中。我后来做的是:

if (pAnimate)
{
    std::thread t1[&] {
        loadBones(meshIndex, mesh, bones);
    });
    t1.join();
}

上面的 lambda 函数有 [&] 表示我们将所有内容作为引用传递,以确保不会创建任何副本。为了防止'touching' loadBones(..) 函数中的数据受到任何外力,我在函数中安装了一个互斥体,如下所示:

void ModelLoader::loadBones(uint meshIndex, const aiMesh *mesh, std::vector<VertexBoneData> &bones)
{
    std::mutex mut;
    std::lock_guard<std::mutex> lock(mut);

    // load bones
}

这只是一个快速而肮脏的修复。它可能不适用于所有人,并且不能保证该程序 运行 不会崩溃。

以下是一些测试结果:

Sans threading & mutex: program runs 0 out of 3 times in a row

With threading; sans mutex: program runs 2 out of 3 times in a row

With threading & mutex: program runs 3 out of 3 times in a row

如果您使用 Linux,请记住 link pthread 以及 <thread><mutex>。欢迎对线程优化提出建议!