Archiv verlassen und diese Seite im Standarddesign anzeigen : Rendern & Rechnen mit DX
Ich habe ein kleines Projekt angefangen, bei dem ich ich etwas berechne (fortlaufend, so Physics Engine artig) und das in einem GUI auch gleich per Direct3D anzeige.
Da ich nur bedingt Wert auf Geschwindigkeit lege und ich eine limitierte Zeitressource habe, programmiere ich mit Visual Baisc .NET und managed DirectX. Die Grafikausgabe erfolgt in einer PictureBox.
Die Berechnung, die Render-Engine (absolut trivial, nur etwa 10 Shpere-Meshes) und das GUI brauchen einen Thread. Die Berechnung läuft und gleichzeitig wird es natürlich auch dargestellt. Das hat am Anfang ziemlich stark geruckelt bis ich herausgefunden habe, dass der Berechnungs-Thread dem Render-Thread die CPU-Power wegschnappt --> Priorität des Berechnungs-Threads auf "Lowest" brachte Abhilfe.
Leider ruckelt das ganze immer noch ein bisschen. Und ich habe das Gefühl, dass irgend etwas an meinen Prinzipien falsch ist.
Oder liegts doch nur am Code und die Grundüberlegung ist gar nicht so falsch?
du bist sicher nicht der einzigste der threads für die den mainloop nutzt... ich persöhnlich halte davon nicht viel. ich hab VB eigentlich noch nie genutzt (vor allem nicht für 3D-Anwendung) aber ich rate dir einfach mal einen normalen gameloop ohne threads zu erstellen und die aufgaben nacheinander abzuschliessen anstatt "gemeinsam", also in etwa so:
while(GAME_RUNNING)
{
delta=time.update();
engine.update(delta);
input.update(delta);
render.update(delta);
windows.update(delta);
}
das muss dein problem zwar nicht lösen, kann es aber. threads im mainloop können ("können", müssen nicht) dir noch ziemlich probleme bereiten vor allem weil du nicht genau steuern kannst daß einige Aufgaben vor anderen erledigt werden - ich würd es einfach mal testen, nutzt du keine threads und es läuft immernoch langsam liegts an deinem code (wenn du nicht viel renderst woran erkennst du daß es langsam läuft? framecounter? wenn ja, was ist da langsam für dich?)
Eigentlich ist es so, dass ich bis Gestern Nachmittag die Render-Funktion von der Engine habe aufrufen lassen, aber im gleichen Thread. Leider stockte die Grafik dann. Ausserdem sackt die CPU-Last bei grossem Screen auf etwa 50% zusammen, weil das Programm immer wartet bis das aktuelle Bild fertig gerendert ist. Bei mehreren Threads könnte ja die Graka rendern (was nahezu keine CPU verbraucht, aber doch Zeit) und die Engine weiterrechnen. Das ist eigentlich die Idee. Der Renderer nimmt dann immer die aktuellen Daten zum Darstellen. Das funktioniert soweit bis auf die Tatsache, dass bei mir (beim Kollegen nicht) ein bisschen ruckelt. Wenn ich den PC erst gerade eingeschalten haben ist es sogar ziemlich schlimm. Mit der Zeit gehts dann.
Könnte es vielleicht auch an der Synchronisation zwischen den Threads liegen? Die ist momentan nämlich überhaupt nicht abgesichert gegen gleichzeitiges Lesen/Schreiben (hat aber komischerweise bis jetzt noch keinen einzigen Fehler gegeben).
Könnte es vielleicht auch an der Synchronisation zwischen den Threads liegen? Die ist momentan nämlich überhaupt nicht abgesichert gegen gleichzeitiges Lesen/Schreiben (hat aber komischerweise bis jetzt noch keinen einzigen Fehler gegeben).
das ist ja das problem was ich meinte: wann wird was getan. stell dir vor du hast ein thread welche die zeit updatet und demnach die frames der animationen wählt, 3D-Objekte verschiebt etc. (also nur die bewegung etc. berechnet, sie nicht rendert). Dann hast du einen render thread welcher durch die objekte looped und jedes objekt rendert, also den ani-frame welcher vom anderen thread gewählt wurde, objectA and die position welcher nach der zeit berechnet wurde etc. - und jetzt laufen die beiden threads gleichzeitig: ThreadA ändert 1000 objekte in deiner welt, währenddessen rendert ThreadB die 1000 objekte. wer sagt dir jetzt das objectX welches gerendert wird schon geupdatet wurde? vielleicht braucht ThreadA in allen bereichen länger als ThreadB und somit werden die objekte teilweise so gerendert wie im cycle davor. und da gibt es 1000 situationen wo was falsch laufen kann (du meintest ja du machst irgentwas mit physik, da gibts sicherlich einige berechnungen die auch etwas cpu in anspruch nehmen), deswegen arbeite ich persöhnlich auch ohne threads (zumindest nicht in solchen bereichen wo es wichtig ist die reihenfolge der aktionen zu steuern). Aber wie gesagt, ich arbeite wenig bis kaum mit Threads und es gibt sicher einige die hier ihren Vorteil ziehen...
du meintest ja du machst irgentwas mit physik, da gibts sicherlich einige berechnungen die auch etwas cpu in anspruch nehmen
Etwa 99%, um genau zu sein.
Das ist die Hauptaufgabe des Programms.
Aber wegen der Synchronisation: Ich hatte eher an Schwierigkeiten des Programmcodes gedacht.
Aber deine Argumentation ist natürlich auch richtig, sofern man nicht noch mehr Informationen besitzt:
Beim Rendern werden die Daten etwa 70 Mal pro Sekunden abgerufen, hingegen etwa 30000 mal geändert, was dann deinen genannten Effekt verstärkt. Allerdings ist das Ruckeln recht gut merkbar, wenn man bedenkt, dass die verschiebungen absolut minimal sein sollten (bei 70 fps nicht beobachtbar, denn die Objekte bewegen sich in einigermassen realtime mit gut beobachtbarer Geschwindikeit über den Bildschirm).
Ausserdem nimmt das Ruckeln stark zu, wenn die Grafikfläche grösser wird. In diesem Zusammenhang muss ich dir alleridngs zustimmen, dass dann die Framezahl auf 40 sinkt, was aber immer noch keine merklichen Ungereimtheiten zu Tage bringen sollte.
Ich vermute eher, dass es daran liegt, dass der Rendering-Prozess zu wenig CPU bekommt (obwohl er schon sehr wenig braucht). Deshalb habe ich ja auch mal die Thread-Priority heruntergesetzt beim Berechnungs-Thread. Das hat dann das Stocken eifach stark eingeschränkt, aber nicht verschwinden lassen.
Gibt es keine Möglichkeit die CPU von Anfang an aufzuteilen? Mein Kollege hat einen Intel P4 mit HT --> 50% CPU-Last, weil in einer virtuellen CPU gerechnet und in der anderen gerendert wird. Bei ihm stockts dann logischerweise auch nicht.
EDIT:
Ich habe mal die Render-Funktion so eingestellt, dass si etwas willkürliches, nichts mit den Engine-Daten in kontakt stehendes, rendert (eine Kugel mit Elliptischer Bahn). Es ruckelt exakt genau gleich wie mit Datenkoppelung.
Zeig mal den Code deiner Threads. Wahrscheinlich detachtst du deine Threads falsch (oder gar nicht).
Zeig mal den Code deiner Threads. Wahrscheinlich detachtst du deine Threads falsch (oder gar nicht).
Ich kann schon den code hier als RAR posten. Um zu verstehen, was abläuft muss man sich allerdings in etwa 500 von gesamthaft ca. 1500 Zeilen Code einlesen...Von dem her bringt es eigentlich gar nichts.
Den Render-Code kann ich allerdings posten:
Do Until Status = RenderStatus.AbortRequest Or Status = RenderStatus.SuspendRequest
myDevice.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, Color.DarkGreen, 1.0F, 0)
myDevice.BeginScene()
index = 0
For Each puck In myEngine.GetPucks
myDevice.Transform.World = Matrix.Translation(CType(puck.Position.x, Single), CType(puck.Position.y, Single), 0)
Spheres(index).DrawSubset(0)
index += 1
Next
myDevice.EndScene()
myDevice.Present()
FrameCount += 1
If Status = RenderStatus.ResetRequest Then
Status = RenderStatus.Running
Me.DisposeRenderer()
Me.Initialize(myEngine)
End If
Loop
PS: Auf meinem Webspace ( http://obelix.gymliestal.ch/~reto.grieder/ ) sind sonst noch der ganze Code inkl. Binaries. DX managed wird allerdings benötigt!
Dir fehlt noch sowas: Thread.Sleep(time). Ansonsten verbraucht dein Renderthread die meiste Zeit und die anderen Threads bekommen zu wenig ab vom Roundtrip.
Dir fehlt noch sowas: Thread.Sleep(time). Ansonsten verbraucht dein Renderthread die meiste Zeit und die anderen Threads bekommen zu wenig ab vom Roundtrip.
Ich habe thread.sleep(time) schon in sehr vielen Varianten ausprobiert, allerdings auf den anderen Thread angewendet. Der Render-Thread braucht ja nur ca. 0.1% der CPU --> Das gibt keine Probleme.
Das Problem an der Funktion sleep ist, dass 1ms das absolute Minimum ist (auch mit einem TimeSpan-Objekt). Dann muss ich das irgendwie so in den Berechnungs-Thread einbauen, dass nicht zu viel und nicht zu wenig geschlafen wird. Leider werden während 1ms die Threads mehr als nur 1 mal gewechselt --> in den meisten Situationen bekommt der Render-Thread immer noch zu wenig CPU, obwohl die Priority 2 Stufen höher ist als beim anderen Thread.
Yo, das ist aber nunmal so mit Threads, das BS beeinflußt diese sehr stark. Man kann zwar Synchronisationsmechanismen einführen aber dennoch ist die eigene Beeinflußung eher gering.
Ich werde mal versuchen die Berechnung so umzuschreiben, dass ein CallBack alle 10ms (z.B.) die Berechnung aufruft und dieses dann eine bestimmte Anzahl Schleifen durchläuft. Wenn die Berechnung weniger als 10ms dauert, dann sollte die CPU-Last unter 100% sinken und den Render-Thread vielleicht nicht so ausbremsen.
Allerdings kann das noch etwas dauer, da ich im Moment noch andere Probleme habe.
vBulletin® v3.8.6, Copyright ©2000-2012, Jelsoft Enterprises Ltd.