C++ 在第二个线程上加载OpenGL资源
我在OpenGL 2.1中使用win32线程。我试图实现的是在背景中加载整个3D场景时,渲染简单的图像,并显示“加载”。它现在可以工作了,但我有一个问题,有时候我的立方体贴图纹理的一部分会从Mozilla Firefox浏览器中获取数据(这到底是怎么发生的?),而忽略那个小盒子,有纹理的话,它只是一个精灵,应该在那里 这种情况在我尝试加载程序的3次中有1次发生。 这是我的线程的外观:C++ 在第二个线程上加载OpenGL资源,c++,multithreading,opengl,C++,Multithreading,Opengl,我在OpenGL 2.1中使用win32线程。我试图实现的是在背景中加载整个3D场景时,渲染简单的图像,并显示“加载”。它现在可以工作了,但我有一个问题,有时候我的立方体贴图纹理的一部分会从Mozilla Firefox浏览器中获取数据(这到底是怎么发生的?),而忽略那个小盒子,有纹理的话,它只是一个精灵,应该在那里 这种情况在我尝试加载程序的3次中有1次发生。 这是我的线程的外观: WindowsThread::WindowsThread(HGLRC graphicsContext, HDC
WindowsThread::WindowsThread(HGLRC graphicsContext, HDC deviceContext) :
graphicsContext_(graphicsContext),
deviceContext_(deviceContext),
running_(false),
task_(0),
mode_(WT_NORMAL)
{
handle_ = CreateThread(0, 0,
(unsigned long (__stdcall *)(void *)) this->staticRun,
(void*) this, CREATE_SUSPENDED, &id_);
if (handle_ == 0) {
LOGE("Unable to create thread.");
return;
}
if (!SetThreadPriority(handle_, THREAD_PRIORITY_NORMAL)) {
LOGE("Unable to set thread priority for thread.");
return;
}
}
WindowsThread::~WindowsThread() {
finishTask();
running_ = false;
WaitForSingleObject(handle_, INFINITE);
CloseHandle(handle_);
wglDeleteContext(graphicsContext_);
}
void WindowsThread::start() {
running_ = true;
if (!ResumeThread(handle_)) {
LOGW("Unable to resume thread.");
}
}
bool WindowsThread::isRunning() {
return running_;
}
void WindowsThread::setTask(Task* task, Mode mode) {
finishTask();
task_ = task;
mode_ = mode;
}
bool WindowsThread::hasTask() {
return task_ != 0;
}
void WindowsThread::finishTask() {
while (task_ != 0) {
Sleep(1);
}
}
void WindowsThread::stop() {
running_ = false;
}
int WindowsThread::staticRun(void* thread) {
return ((WindowsThread*) thread)->run();
}
int WindowsThread::run() {
wglMakeCurrent(deviceContext_, graphicsContext_);
while (running_) {
if (task_ != 0) {
task_->run();
task_ = 0;
}
Sleep(10);
}
wglMakeCurrent(0, 0);
return 1;
}
线程管理器:
WindowsThreadManager::WindowsThreadManager(
System* system, UINT threadPoolSize)
{
if (threadPoolSize == 0) {
SYSTEM_INFO info;
GetSystemInfo(&info);
threadPoolSize = info.dwNumberOfProcessors;
if (threadPoolSize == 0) {
threadPoolSize = 1;
}
}
LOGI("Number of threads used: %d", threadPoolSize);
masterContext_ = wglGetCurrentContext();
HDC hdc = wglGetCurrentDC();
for (UINT i = 0; i < threadPoolSize; i++) {
HGLRC threadContext = wglCreateContext(hdc);
wglShareLists(masterContext_, threadContext);
WindowsThread* thread = new WindowsThread(threadContext, hdc);
thread->start();
threads_.push_back(thread);
}
}
WindowsThreadManager::~WindowsThreadManager() {
for (UINT i = 0; i < threads_.size(); i++) {
delete threads_[i];
}
for (UINT i = 0; i < tasks_.size(); i++) {
delete tasks_[i];
}
}
void WindowsThreadManager::execute(Task* task, Mode mode) {
WindowsThread::Mode wtMode = WindowsThread::WT_NORMAL;
if (mode == TM_GRAPHICS_CONTEXT) {
wtMode = WindowsThread::WT_GRPAHICS_CONTEXT;
}
tasks_.push_back(task);
for (UINT i = 0; i < threads_.size(); i++) {
if (!threads_[i]->hasTask()) {
threads_[i]->setTask(task, wtMode);
return;
}
}
threads_[0]->setTask(task, wtMode);
}
void WindowsThreadManager::joinAll() {
for (UINT i = 0; i < threads_.size(); i++) {
if (threads_[i]->hasTask()) {
threads_[i]->finishTask();
}
}
}
WindowsThreadManager::WindowsThreadManager(
系统*系统,UINT线程池大小)
{
if(threadPoolSize==0){
系统信息;
GetSystemInfo(&info);
threadPoolSize=info.dwNumberOfProcessors;
if(threadPoolSize==0){
threadPoolSize=1;
}
}
LOGI(“使用的线程数:%d”,线程池大小);
masterContext_u2;=wglGetCurrentContext();
HDC HDC=wglGetCurrentDC();
对于(UINT i=0;i开始();
螺纹。推回(螺纹);
}
}
WindowsThreadManager::~WindowsThreadManager(){
对于(UINT i=0;ihasTask()){
线程[i]->setTask(任务,wtMode);
返回;
}
}
线程[0]->setTask(任务,wtMode);
}
void WindowsThreadManager::joinAll(){
对于(UINT i=0;ihasTask()){
线程[i]->finishTask();
}
}
}
我在Winodws 8上使用带有最新驱动程序的Nvidia 670GTX。
你知道问题出在哪里吗
[EDIT]我在加载程序线程的末尾添加了glFinish(),现在所有内容都正常加载。我在某个地方看到,OpenGL并没有立即完成它的所有工作,所以我猜是这样的,在它完成它的工作之前,上下文被设置为NULL
它现在可以工作了,但我有一个问题,有时我的立方体贴图纹理的一部分会从Mozilla Firefox浏览器获取数据(这到底是怎么发生的?)
纹理从未初始化的图形内存接收数据,该内存很可能包含以前使用该内存区域的另一个进程的剩余图像。这样的事情可能会发生,如果
a) 驱动程序有一个bug,不能在线程之间同步资源
及
b) 如果您试图修改纹理,而它绑定到另一个线程中的纹理单元
编辑:您可以(也应该)自己引入适当的同步。只是因为它提高了性能。当纹理当前不忙时,用于在线程之间进行通信。理想情况下,您可以使用两个或多个纹理,以循环方式进行更新。请注意,opengl和线程通常不会同时使用。是的,我对此非常感兴趣。事实上,我之前已经实现了两个上下文,一个是我渲染的,另一个是我加载了资源,当加载资源时,我只是将该上下文作为主上下文,同时删除最后一个主上下文。这没有任何问题。@B:OpenGL和多线程都可以完成,但要正确操作并不简单。@datenwolf是的,但如果我理解这篇文章,他是在线程中创建纹理(或者他在线程中渲染某些内容?)。因为这是随机发生的(三次尝试中有一次),这表明他没有做对,并创造了某种竞赛条件。@Bааћ:是的,这很可能是竞赛条件,但他在共享纹理空间中使用了上下文。这意味着OpenGL实现的负担是在纹理管理中引入正确的同步点。最糟糕的情况应该是丢弃的帧,而不是导致从未初始化内存中获取数据的竞争条件。如果我理解正确,您建议只使用一个上下文,并在我使用它的地方同步所有部分,以便不存在任何竞争条件?或者使用多个上下文,但仍在同步我自己,这样opengl驱动程序就不必了?@SMGhost:不!使用两个上下文(不要在线程之间玩烫手山芋)。但是使用条件变量,以便更新线程知道何时可以安全地修改纹理的内容。如果尚未使用glTexSubImage2D,也可以使用它。在循环循环中保留2或3个纹理,在绘制之前将纹理更新一个索引。目前没有任何情况下,一旦加载纹理就会被修改,之后,在加载资源后,所有图形操作仅在具有单个上下文的主线程上工作。我尝试实现整个场景加载机制的方式是,加载程序线程加载的内容在加载整个资源之前不会被主线程使用,然后我从这些资源开始渲染。我假设在这种情况下不需要条件变量?:)@啊,好的。我以为你的意图是创造一个视频播放器。在这种情况下,不需要条件变量。