动画产生intel_drm错误

Animations producing intel_drm errors

本文关键字:drm 错误 intel 动画      更新时间:2023-10-16

我正在使用Assimp的模型加载器中实现动画;c++/OpenGL渲染。我一直在关注这个教程:http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html。可以这么说,我并没有完全遵循教程,因为在代码方面有一些我不同意的地方,所以我改编了它。请注意,我没有使用作者使用的任何数学成分,所以我使用了glm。无论如何,问题是我的程序有时运行,有时不运行。当我运行我的程序时,它会运行,然后立即崩溃,而在其他时候,它只是正常运行。

要考虑的几件事:

  1. 在添加动画/加载骨骼之前,模型加载器工作得很好,模型加载不会造成任何崩溃;

  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,因为它使用了我认为有缺陷的原始数组:

struct VertexBoneData{向量boneIDs;向量权重;

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);
}

};

现在,我不完全确定是什么导致了崩溃,但最让我困惑的是,有时程序会运行(这意味着代码不一定是罪魁祸首)。所以我决定进行一次调试,包括检查每个骨头(我跳过了一些;有大量的骨头!),并发现在所有的骨头都被加载后,我会得到这个非常奇怪的错误:

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

,有时我会得到这个错误:

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

,有时我会从glm中获得关于vec4实例化的segfault;

,有时……我的程序从来没有崩溃过!

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

我没有使用任何多线程,但它已经闪过我的脑海。我认为这可能是CPU无法处理如此多的数据,因此机会运行。如果我实现线程,这样骨加载是在另一个线程上完成的;或者更好的是,使用互斥锁,因为我发现,通过缓慢调试应用程序,程序可以运行,这是有意义的,因为每个任务都被分解成块;这就是互斥锁在技术上的作用。

为了讨论的方便,我的技术规格:

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函数有[&]表示我们将所有内容作为引用传递,以确保没有创建副本。为了防止任何外力"接触"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,请记住链接pthread以及包括<thread><mutex>。欢迎对线程优化提出建议!