2013-02-14 7 views
6

Uso i thread win32 con OpenGL 2.1. Quello che sto cercando di ottenere è di rendere l'immagine semplice che dice "caricamento", mentre sullo sfondo viene caricata tutta la scena 3D. Funziona ora, ma ho un problema, dove a volte una parte della mia trama cubemap prende dati da Mozilla Firefox Browser (Come diavolo succede? ???) e ignori quella piccola scatola, con texture, è solo uno sprite e è dove dovrebbe essere .: enter image description hereCaricamento risorse OpenGL sul secondo thread

Questo accade come 1 su 3 volte provo a caricare il mio programma. Ecco come il mio filo appare:

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

Io uso Nvidia 670GTX con gli ultimi driver su Winodws 8. Tutte le idee in cui il problema potrebbe essere?

[EDIT] Ho aggiunto glFinish() alla fine della mia discussione del caricatore, e ora tutto si carica normalmente. Sono rosso da qualche parte, che OpenGL non finisce immediatamente tutto il suo lavoro, quindi credo che questo fosse il caso, dove il contesto era impostato su NULL prima che potesse finire il suo lavoro.

+1

prendere nota che opengl e thread di solito non vanno avanti –

+0

Sì, ho molto rosso su questo. In effetti, avevo implementato due contesti prima, su uno dei rendering, sull'altro ho caricato le risorse e quando le risorse sono state caricate ho appena preso quel contesto e ne ho fatto il contesto principale, eliminando l'ultimo contesto principale. Questo ha funzionato senza problemi. – SMart

+0

@ BЈовић: OpenGL e multithreading possono essere eseguiti, non è semplice per ottenere il diritto. – datenwolf

risposta

7

ora funziona, ma ho un problema, dove a volte una parte della mia cubemap trama prende i dati da Mozilla Firefox Browser (Come diavolo fa questo accada ???)

vostra struttura riceve dati dalla memoria grafica non inizializzata, che molto probabilmente può contenere immagini residue da un altro processo, che in precedenza utilizzava quella regione di memoria. Roba come questo può accadere, se

a) il conducente ha un bug e non sincronizza le risorse tra i thread

e

b) se si sta cercando di modificare una texture, mentre è legata a un'unità di trama nell'altro thread.

MODIFICA: È possibile (e dovrebbe) introdurre la sincronizzazione corretta da soli. Semplicemente perché migliora le prestazioni. Utilizzare condition variables per comunicare tra thread, quando la trama non è attualmente occupata. Idealmente si usano due o più trame, si aggiorna in modo round robin.

+0

La tua risposta mi ha aiutato a trovare un problema reale, grazie ^^ – SMart

+0

@SMGhost: Si prega di vedere anche la mia modifica aggiunta. – datenwolf

+0

Se ho capito bene, suggerisci di utilizzare un solo contesto e sincronizzare tutte le parti in cui lo utilizzo, in modo che non ci siano condizioni di gara? O usando più contesti, ma continuando a sincronizzarmi, quindi il driver opengl non dovrebbe? – SMart

Problemi correlati