cudaGraphicsGLRegisterBuffer verursacht deadlock

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

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 :(
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von CodingCat »

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
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: 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.
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?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

CodingCat hat geschrieben:
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
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.
Die ursprüngliche implementierung war einfach:

Code: Alles auswählen

glBufferData(GL_TEXTURE_BUFFER, poolSize* sizeof(bufferType) * 8, NULL, GL_STATIC_DRAW);
poolSize kann sich jeden Frame ändern und wenn die größer ist dann wird eben der Buffer neu mit 0 initialisiert.
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.

CodingCat hat geschrieben:
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.
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?
Ü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.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von CodingCat »

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.
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?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

CodingCat hat geschrieben:
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.
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?
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.

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
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von CodingCat »

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
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

Grad probiert:
Hat zur Folge dass die Anwendung schon vor dem Resize stirbt....
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von CodingCat »

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
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

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
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

So Funktionierts:

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);
So nicht mehr

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");
Soblad ich den Buffer bei CUDA registriere und sonst nichts an der Anwendung ändere krachts :(
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Matthias Gubisch
Establishment
Beiträge: 506
Registriert: 01.03.2009, 19:09

Re: cudaGraphicsGLRegisterBuffer verursacht deadlock

Beitrag von Matthias Gubisch »

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.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
Antworten