6

私はOpenGL2.1でwin32スレッドを使用しています。私が達成しようとしているのは、バックグラウンドで3Dシーン全体がロードされている間に、「ロード中」という単純な画像をレンダリングすることです。今は動作しますが、問題があります。キューブマップテクスチャの一部がMozilla Firefoxブラウザからデータを取得し(一体どうやってこれが起こるのでしょうか?)、テクスチャのある小さなボックスを無視すると、それは単なるスプライトであり、それがあるべき場所です。: ここに画像の説明を入力してください

これは、プログラムをロードしようとすると3回に1回のように発生します。これは私のスレッドがどのように見えるかです:

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

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

Winodws8で最新のドライバーを搭載したNvidia670GTXを使用しています。問題が発生する可能性のあるアイデアはありますか?

[編集]ローダースレッドの最後にglFinish()を追加しましたが、すべてが正常に読み込まれるようになりました。私はどこかで赤くなりましたが、OpenGLはすべての作業をすぐに終了するわけではないので、作業を終了する前にコンテキストがNULLに設定されていたのはこの場合だったと思います。

4

1 に答える 1

7

今は動作しますが、キューブマップテクスチャの一部がMozilla Firefoxブラウザからデータを取得することがあるという問題があります(これは一体どうやって起こるのですか?)

テクスチャは、初期化されていないグラフィックメモリからデータを受け取ります。このメモリには、以前にそのメモリ領域を使用していた別のプロセスからの残差画像が含まれている可能性があります。このようなことが起こる可能性があります

a)ドライバーにバグがあり、スレッド間でリソースを同期しない

b)他のスレッドのテクスチャユニットにバインドされているときに、テクスチャを変更しようとしている場合。

編集:適切な同期を自分で導入することができます(そして導入する必要があります)。パフォーマンスが向上するからです。テクスチャが現在ビジーでない場合は、条件変数を使用してスレッド間で通信します。理想的には、2つ以上のテクスチャを使用し、ラウンドロビン方式で更新します。

于 2013-02-14T11:14:18.543 に答える