gpt4 book ai didi

c++ - OpenGL多线程

转载 作者:太空狗 更新时间:2023-10-29 22:58:29 25 4
gpt4 key购买 nike

好的,我正在尝试将我的游戏引擎切换到多线程。我已经研究了如何在多线程应用程序中使用 OpenGL。我对渲染或切换上下文没有问题。让我的一段代码解释问题 :) :

for (it = (*mIt).Renderables.begin(); it != (*mIt).Renderables.end(); it++)
{
//Set State Modeling matrix
CORE_RENDERER->state.ModelMatrix = (*it).matrix;
CORE_RENDERER->state.ActiveSubmesh = (*it).submesh;

//Internal Model Uniforms
THREAD_POOL->service.post([&]
{
for (unsigned int i = 0; i < CORE_RENDERER->state.ActiveShaderProgram->InternalModelUniforms.size(); i++)
{
CORE_RENDERER->state.ActiveShaderProgram->InternalModelUniforms[i]->Set( CORE_RENDERER->state.ModelMatrix);
}

CORE_RENDERER->state.ActiveSubmesh->_Render();
});

//Sleep(10);
}

我将快速解释代码中的元素,以使我的问题更加清楚。 Renderables 是一个简单的 std::vector 元素,具有 _Render() 功能,效果很好。 CORE_RENDERER->state 是一个包含当前渲染状态信息的结构,例如当前 Material 属性和当前子网格 ModelMatrix。所以 Matrix 和 Submesh 被存储到状态结构(我知道这很慢,我可能会及时改变它:))下一段代码被发送到 THREAD_POOL->service ,它实际上是 boost::asio::io_service 和只有一个线程,所以它就像一个渲染命令队列。这个想法是主线程提供有关渲染内容和进行视锥体剔除和其他测试的信息,而辅助线程进行实际渲染。这工作正常,除了有一个小问题:

发送到线程池的代码开始执行,但在设置所有 InternalModelUniforms 并渲染子网格之前,将执行下一次迭代 Renderables 并更改 ModelMatrix 和 ActiveSubmesh。该程序不会崩溃,但两种信息都会发生变化,并且会呈现一些网格,一些矩阵是正确的,而另一些则不是,这会导致图像闪烁。对象出现在帧上,下一帧它们就消失了。问题只有在我启用 Sleep(10) 函数时才能解决,该函数确保代码在下一次迭代之前执行,这显然扼杀了获得性能的想法。最好的解决方案是什么?如何将命令发送到队列,每个命令都具有唯一的内置数据?也许我需要在没有 io_service 的情况下实现自己的命令队列和单线程?

我会继续我的研究,因为我知道有办法。这个想法是正确的,因为我得到了性能提升,因为渲染线程没有处理单个 if/else 语句:)任何帮助或提示都会很有帮助!

谢谢!

enter image description here

更新:

经过几个晚上的努力,我创建了一个非常原始的主线程和辅助线程之间的通信模型。我创建了一个类,表示要由辅助线程执行的基本命令:

class _ThreadCommand
{
public:
_ThreadCommand() {}
~_ThreadCommand() {}

virtual void _Execute() = 0;
virtual _ThreadCommand* Clone() = 0;
};

这些命令是此类的子命令,具有 _Execute() 函数来执行需要完成的任何操作。渲染时的主线程填充这些命令的 boost::ptr_vector 而辅助线程继续检查是否有任何命令要处理。当找到命令时,它会将整个 vector 复制到 _AuxThread 中它自己的 vector 并清除原始 vector 。然后通过在每个命令上调用 _Execute 函数来执行命令:

void _AuxThread()
{
//List of Thread commands
boost::ptr_vector<_ThreadCommand> _cmd;

//Infinitive loop
while(CORE_ENGINE->isRunning())
{
boost::lock_guard<boost::mutex> _lock(_auxMutex);
if (CORE_ENGINE->_ThreadCommands.size() > 0)
{
boost::lock_guard<boost::mutex> _auxLock(_cmdMutex);
for (unsigned int i = 0; i < CORE_ENGINE->_ThreadCommands.size(); i++)
{
_cmd.push_back(CORE_ENGINE->_ThreadCommands[i].Clone());
}

//Clear commands
CORE_ENGINE->_ThreadCommands.clear();

//Execute Commands
for (unsigned int i = 0; i < _cmd.size(); i++)
{
//Execute
_cmd[i]._Execute();
}

//Empty _cmd
_cmd.clear();
}
}

//Notify main thread that we have finished
CORE_ENGINE->_ShutdownCondition->notify_one();
}

我知道这是一个非常糟糕的方法。性能相当慢,我很确定这是因为所有的复制和互斥锁。但至少渲染器可以工作。您可以了解我想要实现的目标,但正如我所说,我对多线程非常陌生。这种情况的最佳解决方案是什么?我应该使用 asio::io_service 返回到 ThreadPool 系统吗?如何将必须发送到渲染器的所有值的命令提供给 AuxThread,以便以正确的方式执行任务?

最佳答案

首先,一个警告。你的“小问题”一点都不小。这是竞争条件,这是 C++ 中的未定义行为,反过来又意味着任何事情都可能发生,包括:

  • 一切都很好

  • 图像闪烁

  • 什么都不渲染

  • 它会在每个月的最后一个星期六崩溃。或者在你的电脑上工作正常,但在其他人的电脑上崩溃。

说真的,永远不要依赖 UB,尤其是在编写库/框架/游戏引擎时。

现在谈谈你的问题。

让我们抛开您的方法的任何实际好处并首先修复它。

实际上,OpenGL 实现在底层使用了非常相似的东西。命令由驱动程序线程异步执行。我建议您阅读有关它们的实现的信息,以获得有关如何改进设计的一些想法。

您需要做的是以某种方式“捕获”您发布 渲染命令时的状态。最简单的事情 - 将 CORE_RENDERER->state 复制到闭包中并使用此拷贝进行渲染。不过,如果 state 足够大,它的成本可能会很高。

另一种解决方案(OpenGL 采用这种方式)是使 state 中的每个更改也成为命令,因此

CORE_RENDERER->state.ModelMatrix = (*it).matrix;
CORE_RENDERER->state.ActiveSubmesh = (*it).submesh;

翻译成

Matrix matrix = (*it).matrix;
Submesh submesh = (*it).submesh;

THREAD_POOL->service.post([&,matrix,submesh]{
CORE_RENDERER->state.ModelMatrix = matrix;
CORE_RENDERER->state.ActiveSubmesh = submesh;
});

但是请注意,现在您不能简单地从主线程读取 CORE_RENDERER->state.ModelMatrix,因为它在不同的线程中发生变化。您必须首先确保命令队列为空。

关于c++ - OpenGL多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40289825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com