【问题标题】:Animations producing intel_drm errors产生 intel_drm 错误的动画
【发布时间】:2015-12-04 03:32:58
【问题描述】:

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

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

};

现在,我不完全确定导致崩溃的原因,但最让我困惑的是有时程序会运行(暗示代码不一定是罪魁祸首)。所以我决定做一个 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 问题,因为它无法一次处理这么多数据,这导致了这次崩溃。我的理论是,由于它无法处理那么多数据,因此这些数据永远不会分配给向量。

我没有使用任何多线程,但它已经越过我的脑海。我认为这可能是 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 错误?

【问题讨论】:

  • 在编写本教程时,我使用了 NVIDIA GPU。我们需要了解问题是否与 MESA 驱动程序有关(驱动程序错误或应用程序端的某些东西可能没有正确实现但不知何故传递给 NVIDIA)。您是否有机会获取此代码并在 NVIDIA 上运行它?另外,您是否尝试使用 GDB 运行它?
  • 不幸的是,我没有一台配备 NVIDIA GPU 的机器(我曾经使用过)。但这就是有趣的地方;我将骨骼加载代码封装到它自己的名为loadBones(..) 的函数中,然后将它放在if (pAnimate) 条件内的线程中。有趣的是,我遇到的崩溃数量已大大减少。但是,它仍然会崩溃;因此可以肯定地说,这可能是 CPU/GPU 问题,或者仅仅是缺少多线程。

标签: c++ opengl animation assimp


【解决方案1】:

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

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

上面的 lambda 函数有 [&amp;] 表示我们将所有内容作为引用传递,以确保不会创建任何副本。为了防止任何外力“接触”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 以及包括 &lt;thread&gt;&lt;mutex&gt;。欢迎提出关于线程优化的建议!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 2013-07-16
    • 2012-03-09
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多