cudaGraphicsGLRegisterBuffer verursacht deadlock
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
cudaGraphicsGLRegisterBuffer verursacht deadlock
Wie das Thema vermuten lässt ärgere ich mich aktuell mit der Kombination CUDA-OpenGL rum.
Konkret geht es darum von OpenGL befüllte Buffer mit Cuda zu bearbeiten, das Ergebnis in einer Textur zu Speichern und diese am Ende wieder mit OpenGL auf ein Fullscreen Quad zu pinseln.
Dazu möchte ich folgenden Ablauf implementieren.
1) erzeuge alle Buffer mit glGenBuffers() allokiere den Speicher und intialisiere mit 0. Zwei der Buffer haben immer Windowsize und sind vom Typ uint, die anderen sind vom selben Typ allerdings kleiner und ändern jedes Frame ihre Größe
2) Registiere die Buffer mittels cudaGraphicsGLRegisterBuffer() bei CUDA.
-- Initialisierung erledigt
3) Befülle während des Renderdurchgangs die Buffer mittels OpenGL
4) Mappe die Buffer nach Cuda und hole den Pointer
5) Starte den Cuda Kernel und übergebe ihm die DevicePointer der Buffer.
6) Warte bis der CUDA Kernel beendet ist und unmappe die Buffer
Das scheint auch alles zu klappen (ich bekomme gültige pointer, es gibt weder von CUDA noch von OpenGL eine Fehlermeldung zurück oder eine Debugausgabe, auch die beim Mappen zurückgegebene Größe entspricht der erwarteten)
Und zwar solange bis ich Versuche mein Fenster zu vergrößeren.
Beim Resize halte ich zunächst das Rendering an,
Unmappe alle evtl noch gemappten buffer, gib diese frei, und starte wieder bei 1) nur mit neuen Buffergrößen.
Da klappt auch noch soweit ohne Fehler, und anschliesend landen dann sowohl der CUDA als auch der OpenGL Driver in einem Systemaufrauf Namens: ZwWaitForMultipleObjects(), und irgendwann bekomm ich entweder die Meldung: Zu viele Fehler im OpenGL treiben wollens sie "irgend eine Nvidia Seite" besuchen? und die Applikation beendet sich. Das ist die nette Art der Applikation abzuschmieren, die weniger nette ist dass sie das gesamte System einfriert.
Die beiden Buffer die ihre Größe dynamisch ändern funktionieren problemlos, die anderen beiden verursachen die Probleme.
Am VRAM kann es eigentlich nicht liegen. Die Graka hier ist ne GTX 580 mit 3GB, rein rechnerische verbraucht mein Applikation bei Fullscreen ca 300-400MB.
Wenn jemand ne Idee hat oder noch mehr Infos braucht immer her damit, bin für jede Hilfe dankbar da mich das jezt schon 3 Tage meiner kostbaren Zeit gekostet hat :(
Konkret geht es darum von OpenGL befüllte Buffer mit Cuda zu bearbeiten, das Ergebnis in einer Textur zu Speichern und diese am Ende wieder mit OpenGL auf ein Fullscreen Quad zu pinseln.
Dazu möchte ich folgenden Ablauf implementieren.
1) erzeuge alle Buffer mit glGenBuffers() allokiere den Speicher und intialisiere mit 0. Zwei der Buffer haben immer Windowsize und sind vom Typ uint, die anderen sind vom selben Typ allerdings kleiner und ändern jedes Frame ihre Größe
2) Registiere die Buffer mittels cudaGraphicsGLRegisterBuffer() bei CUDA.
-- Initialisierung erledigt
3) Befülle während des Renderdurchgangs die Buffer mittels OpenGL
4) Mappe die Buffer nach Cuda und hole den Pointer
5) Starte den Cuda Kernel und übergebe ihm die DevicePointer der Buffer.
6) Warte bis der CUDA Kernel beendet ist und unmappe die Buffer
Das scheint auch alles zu klappen (ich bekomme gültige pointer, es gibt weder von CUDA noch von OpenGL eine Fehlermeldung zurück oder eine Debugausgabe, auch die beim Mappen zurückgegebene Größe entspricht der erwarteten)
Und zwar solange bis ich Versuche mein Fenster zu vergrößeren.
Beim Resize halte ich zunächst das Rendering an,
Unmappe alle evtl noch gemappten buffer, gib diese frei, und starte wieder bei 1) nur mit neuen Buffergrößen.
Da klappt auch noch soweit ohne Fehler, und anschliesend landen dann sowohl der CUDA als auch der OpenGL Driver in einem Systemaufrauf Namens: ZwWaitForMultipleObjects(), und irgendwann bekomm ich entweder die Meldung: Zu viele Fehler im OpenGL treiben wollens sie "irgend eine Nvidia Seite" besuchen? und die Applikation beendet sich. Das ist die nette Art der Applikation abzuschmieren, die weniger nette ist dass sie das gesamte System einfriert.
Die beiden Buffer die ihre Größe dynamisch ändern funktionieren problemlos, die anderen beiden verursachen die Probleme.
Am VRAM kann es eigentlich nicht liegen. Die Graka hier ist ne GTX 580 mit 3GB, rein rechnerische verbraucht mein Applikation bei Fullscreen ca 300-400MB.
Wenn jemand ne Idee hat oder noch mehr Infos braucht immer her damit, bin für jede Hilfe dankbar da mich das jezt schon 3 Tage meiner kostbaren Zeit gekostet hat :(
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Wie genau ändern die ihre Größe? In DX können Buffers z.B. gar nicht ihre Größe ändern, kA wie CUDA Interop damit umgeht. Wobei es im Moment ja aussieht, als wäre das in diesem Zusammenhang kein Problem.Matthias Gubisch hat geschrieben:1) erzeuge alle Buffer mit glGenBuffers() allokiere den Speicher und intialisiere mit 0. Zwei der Buffer haben immer Windowsize und sind vom Typ uint, die anderen sind vom selben Typ allerdings kleiner und ändern jedes Frame ihre Größe
Hast du das Rendering in einem extra Thread, oder was genau musst du hier anhalten? Wieso musst du hier Buffers unmappen, sollte das nicht automatisch am Ende des aktuellen Render-Prozesses geschehen?Matthias Gubisch hat geschrieben: Beim Resize halte ich zunächst das Rendering an,
Unmappe alle evtl noch gemappten buffer, gib diese frei, und starte wieder bei 1) nur mit neuen Buffergrößen.
Da klappt auch noch soweit ohne Fehler, und anschliesend landen dann sowohl der CUDA als auch der OpenGL Driver in einem Systemaufrauf Namens: ZwWaitForMultipleObjects(), und irgendwann bekomm ich entweder die Meldung: Zu viele Fehler im OpenGL treiben wollens sie "irgend eine Nvidia Seite" besuchen? und die Applikation beendet sich. Das ist die nette Art der Applikation abzuschmieren, die weniger nette ist dass sie das gesamte System einfriert.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Die ursprüngliche implementierung war einfach:CodingCat hat geschrieben:Wie genau ändern die ihre Größe? In DX können Buffers z.B. gar nicht ihre Größe ändern, kA wie CUDA Interop damit umgeht. Wobei es im Moment ja aussieht, als wäre das in diesem Zusammenhang kein Problem.Matthias Gubisch hat geschrieben:1) erzeuge alle Buffer mit glGenBuffers() allokiere den Speicher und intialisiere mit 0. Zwei der Buffer haben immer Windowsize und sind vom Typ uint, die anderen sind vom selben Typ allerdings kleiner und ändern jedes Frame ihre Größe
Code: Alles auswählen
glBufferData(GL_TEXTURE_BUFFER, poolSize* sizeof(bufferType) * 8, NULL, GL_STATIC_DRAW);
In der aktuellen implementierung zerstöre ich den Buffer zuerst vollständig um in dann nochmal komplett neu aufzubauen, um sicherzustellen dass es keinen Unterschied zur Anfangsinitialisierung (bei der ja alles klappt) gibt.
Ürsprünglich war das auch kein Problem, auch das BufferResize funktionierte wie oben.CodingCat hat geschrieben:Hast du das Rendering in einem extra Thread, oder was genau musst du hier anhalten? Wieso musst du hier Buffers unmappen, sollte das nicht automatisch am Ende des aktuellen Render-Prozesses geschehen?Matthias Gubisch hat geschrieben: Beim Resize halte ich zunächst das Rendering an,
Unmappe alle evtl noch gemappten buffer, gib diese frei, und starte wieder bei 1) nur mit neuen Buffergrößen.
Da klappt auch noch soweit ohne Fehler, und anschliesend landen dann sowohl der CUDA als auch der OpenGL Driver in einem Systemaufrauf Namens: ZwWaitForMultipleObjects(), und irgendwann bekomm ich entweder die Meldung: Zu viele Fehler im OpenGL treiben wollens sie "irgend eine Nvidia Seite" besuchen? und die Applikation beendet sich. Das ist die nette Art der Applikation abzuschmieren, die weniger nette ist dass sie das gesamte System einfriert.
Der Rendervorgang wird von aussen durch nen Timer angestoßen, dieser wird angehalten um sicherzugehen dass mir keine Drawcall in den Bufferresize reinspuckt, wenn ich sicher weis dass das mit der Cuda-Interop keine Probleme verursacht werd ich das wohl wieder ausbauen.
Mit unmappen hab ich mich wohl etwas unklar ausgedrückt, ich meinte damit dass ich für jeden der Buffer cudaGraphicsUnmapResources aufrufe (war ursprünglich ebenfallse nicht drinnen) um sicher zu gehen dass der CUDA Kernel die Buffer nicht mehr blockiert und das Problem nicht daher kommt.
cudaGraphicsMapResources und cudaGraphicsUnmapResources stellen ja laut Doku sicher dass Rendercalls bzw Cudakernels abgeschlossen sind bevor der jeweils andere wieder auf die Buffer zugreifen darf.
Leider haben all diese Maßnahmen bisher nicht den gewünschten Erfolg gebracht.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Klar musst du cudaGraphicsMapResources/cudaGraphicsUnmapResources aufrufen, mich wundert nur, dass du das explizit beim Resize tun musst. Sollte beim Resize nicht einfach alle ausstehende Rendering-Aktivität abgeschlossen sein, und somit cudaGraphicsUnmapResources schon im Rahmen des Rendering-Ablaufs für alle Ressourcen aufgerufen worden sein?Matthias Gubisch hat geschrieben:Ürsprünglich war das auch kein Problem, auch das BufferResize funktionierte wie oben.
Der Rendervorgang wird von aussen durch nen Timer angestoßen, dieser wird angehalten um sicherzugehen dass mir keine Drawcall in den Bufferresize reinspuckt, wenn ich sicher weis dass das mit der Cuda-Interop keine Probleme verursacht werd ich das wohl wieder ausbauen.
Mit unmappen hab ich mich wohl etwas unklar ausgedrückt, ich meinte damit dass ich für jeden der Buffer cudaGraphicsUnmapResources aufrufe (war ursprünglich ebenfallse nicht drinnen) um sicher zu gehen dass der CUDA Kernel die Buffer nicht mehr blockiert und das Problem nicht daher kommt.
cudaGraphicsMapResources und cudaGraphicsUnmapResources stellen ja laut Doku sicher dass Rendercalls bzw Cudakernels abgeschlossen sind bevor der jeweils andere wieder auf die Buffer zugreifen darf.
Leider haben all diese Maßnahmen bisher nicht den gewünschten Erfolg gebracht.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Davon bin ich urspünglich ausgegangen, was ich da beschrieben habe ist der aktuelle ablauf nach über 3 Tagen rumprobieren, habs grad nochmal getestet, es macht keinen unterschied ob ich das beim Resize aufrufe oder nicht.CodingCat hat geschrieben:Klar musst du cudaGraphicsMapResources/cudaGraphicsUnmapResources aufrufen, mich wundert nur, dass du das explizit beim Resize tun musst. Sollte beim Resize nicht einfach alle ausstehende Rendering-Aktivität abgeschlossen sein, und somit cudaGraphicsUnmapResources schon im Rahmen des Rendering-Ablaufs für alle Ressourcen aufgerufen worden sein?Matthias Gubisch hat geschrieben:Ürsprünglich war das auch kein Problem, auch das BufferResize funktionierte wie oben.
Der Rendervorgang wird von aussen durch nen Timer angestoßen, dieser wird angehalten um sicherzugehen dass mir keine Drawcall in den Bufferresize reinspuckt, wenn ich sicher weis dass das mit der Cuda-Interop keine Probleme verursacht werd ich das wohl wieder ausbauen.
Mit unmappen hab ich mich wohl etwas unklar ausgedrückt, ich meinte damit dass ich für jeden der Buffer cudaGraphicsUnmapResources aufrufe (war ursprünglich ebenfallse nicht drinnen) um sicher zu gehen dass der CUDA Kernel die Buffer nicht mehr blockiert und das Problem nicht daher kommt.
cudaGraphicsMapResources und cudaGraphicsUnmapResources stellen ja laut Doku sicher dass Rendercalls bzw Cudakernels abgeschlossen sind bevor der jeweils andere wieder auf die Buffer zugreifen darf.
Leider haben all diese Maßnahmen bisher nicht den gewünschten Erfolg gebracht.
Ich bin mir auch nicht sicher ob der Deadlock beim Resize entsteht oder erst beim den nächsten Renderaufrufen.
Das einzige was ich sicher sagen kann ist dass sowohl der CUDA als auch der OpenGL Treiber beim versuch nach einem Resize zu rendern auf irgendwelche Objekte warten.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Und was ist, wenn du einfach die Größe aller Buffers dynamisch änderst?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Grad probiert:
Hat zur Folge dass die Anwendung schon vor dem Resize stirbt....
Hat zur Folge dass die Anwendung schon vor dem Resize stirbt....
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Das ist doch schonmal interessant. Die Frage ist jetzt nur, wo genau. ;)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
Das versuche ich immer noch rauszufinden, sobald ich neue Erkenntise habe werde ich wieder berichten.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
So Funktionierts:
So nicht mehr
Soblad ich den Buffer bei CUDA registriere und sonst nichts an der Anwendung ändere krachts :(
Code: Alles auswählen
if(!m_ABufferPageIdxBufferID)
glGenBuffers(1, &m_ABufferPageIdxBufferID);
glBindBuffer(GL_TEXTURE_BUFFER, m_ABufferPageIdxBufferID);
glBufferData(GL_TEXTURE_BUFFER, m_ScreenWidth * m_ScreenHeight * sizeof(unsigned int), NULL, GL_STATIC_DRAW);
glMakeBufferResidentNV(GL_TEXTURE_BUFFER, GL_READ_WRITE);
glGetBufferParameterui64vNV(GL_TEXTURE_BUFFER, GL_BUFFER_GPU_ADDRESS_NV, &m_ABufferPageIdxAddress);
Code: Alles auswählen
if(!m_ABufferPageIdxBufferID)
glGenBuffers(1, &m_ABufferPageIdxBufferID);
glBindBuffer(GL_TEXTURE_BUFFER, m_ABufferPageIdxBufferID);
glBufferData(GL_TEXTURE_BUFFER, m_ScreenWidth * m_ScreenHeight * sizeof(unsigned int), NULL, GL_STATIC_DRAW);
glMakeBufferResidentNV(GL_TEXTURE_BUFFER, GL_READ_WRITE);
glGetBufferParameterui64vNV(GL_TEXTURE_BUFFER, GL_BUFFER_GPU_ADDRESS_NV, &m_ABufferPageIdxAddress);
cudaError success = cudaGraphicsGLRegisterBuffer(&cuda_ABufferPageIdxBufferID, m_ABufferPageIdxBufferID, cudaGraphicsRegisterFlagsNone );
if(success != cudaSuccess)
VISLIB_ERROR("Could not register m_ABufferPageIdxBufferID");
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
-
- Establishment
- Beiträge: 506
- Registriert: 01.03.2009, 19:09
Re: cudaGraphicsGLRegisterBuffer verursacht deadlock
So ich bin hier glaub ich noch eine Lösung schuldig nachdem ich sie endlich gefunde habe.
Das ganze Problem war ein nicht dokumentiertes Verhalten (zumindest habe ich nichts dergleichen in der dokumentation gefunden) der CUDA-OpenGL interop.
OpenGL kann nämlich nicht in einen Buffer zeichen der bei CUDA registriert ist.
Die Lösung ist damit, nicht wie von mir versucht beim erzeugen des OpenGL-Buffers diesen bei CUDA zu registrieren, jeden Frame zu mappen und unmappen und vor dem zerstören wieder zu deregistrieren, sonder:
Erzeugen den OpenGL-Buffer wie gewohnt.
1x pro Frame:
Führe OGL Rendering aus
Registriere OGL Buffer bei CUDA
Mappe den Buffer
Hohle den gemappten Zeigern
Führe CUDA Kernel aus
Unmappe den Buffer
Unregistriere den Buffer
Die Lösung war in irgend einer 6!!!! Jahre alten Präsenation von Nvidia vergraben, alle neueren Präsentation die ich gefunden habe und auch die Doku beinhalten keinerlei Hinweise auf dieses Verhalten.
Das ganze Problem war ein nicht dokumentiertes Verhalten (zumindest habe ich nichts dergleichen in der dokumentation gefunden) der CUDA-OpenGL interop.
OpenGL kann nämlich nicht in einen Buffer zeichen der bei CUDA registriert ist.
Die Lösung ist damit, nicht wie von mir versucht beim erzeugen des OpenGL-Buffers diesen bei CUDA zu registrieren, jeden Frame zu mappen und unmappen und vor dem zerstören wieder zu deregistrieren, sonder:
Erzeugen den OpenGL-Buffer wie gewohnt.
1x pro Frame:
Führe OGL Rendering aus
Registriere OGL Buffer bei CUDA
Mappe den Buffer
Hohle den gemappten Zeigern
Führe CUDA Kernel aus
Unmappe den Buffer
Unregistriere den Buffer
Die Lösung war in irgend einer 6!!!! Jahre alten Präsenation von Nvidia vergraben, alle neueren Präsentation die ich gefunden habe und auch die Doku beinhalten keinerlei Hinweise auf dieses Verhalten.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben