在第二个线程上加载OpenGL资源

SMG*_*ost 6 c++ opengl multithreading

我在OpenGL 2.1中使用win32线程.我想要实现的是渲染简单的图像说"加载",而在后台整个3D场景正在加载.它现在有效,但我有一个问题,有时我的立方体贴图纹理的一部分从Mozilla Firefox浏览器中获取数据(如何发生这种情况???)并忽略那个带有纹理的小盒子,它只是一个精灵和它应该在哪里: 在此输入图像描述

这种情况发生在我尝试加载程序时的三分之一.这是我的线程的样子:

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;
}
Run Code Online (Sandbox Code Playgroud)

ThreadManager:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我在Winodws 8上使用Nvidia 670GTX和最新的驱动程序.问题可能出在哪里?

[编辑]我在我的加载程序线程的末尾添加了glFinish(),现在一切都正常加载.我在某个地方红了,OpenGL没有立即完成它的所有工作,所以我猜这就是这种情况,其中上下文在它完成它的工作之前被设置为NULL.

dat*_*olf 7

它现在有效,但我有一个问题,有时我的立方体贴图纹理的一部分从Mozilla Firefox浏览器中获取数据(这到底怎么回事?)

您的纹理从未初始化的图形内存接收数据,该内存很可能包含先前使用该内存区域的另一个进程的残留图像.如果这样的事情会发生

a)驱动程序有一个错误,并且不会在线程之间同步资源

b)如果你正在尝试修改纹理,那么它被绑定到另一个线程中的纹理单元.

编辑:您可以(并且应该)自己引入适当的同步.仅仅因为它提高了性能.当纹理当前不忙时,使用条件变量在线程之间进行通信.理想情况下,您使用两个或更多纹理,您以循环方式更新.

  • @SMGhost:不!使用两个上下文(不要使用线程之间的上下文来玩烫手山芋).但是使用条件变量以便更新线程知道何时可以安全地修改纹理的内容.如果你还没有使用它,也可以使用glTexSubImage2D.在循环周期中保留2或3个纹理,您可以在绘制之前更新纹理一个索引. (2认同)