Softwarerasterizer in C# oder VB .Net

Rossibaer

Lieutenant
Registriert
Apr. 2007
Beiträge
754
Hallo zusammen,

wie der Titel schon erahnen läßt, gehts mir um Grafikprogrammierung in C# oder VB .Net. Ich bin fit in beiden Sprachen, also ist es nebensächlich. Nun aber zu dem eigentlichen:

Zuerst meine angestaubte aber immer noch funktionierende Hardware wäre ein Pentium 4 mit 3,4 GHz. 2GB Ram und die Grafikkarte wohl eher unter ferner liefen... Aktuell habe ich eine 1280x1024 Auflösung 32Bit eingestellt.

Softwaremäßig wäre da WinXP SP3 und das Visual Studio 2005 mit .Net Framework 2.0 installiert.

Aktuell bin ich soweit, dass bei den oben genannten Parametern meine FullScreen App mit "satten" 58 FPS läuft. Intern verwende ich zur Darstellung die BufferedGraphics und Bitmap Klassen. Ich versuche so schnell wie möglich ein Foto und ein rotes Dreieck darzustellen. Bei meinen Messungen ergibt sich, dass die CPU ca. 72% der Zeit damit beschäftigt ist, die Graphics.DrawImage Methode auszuführen. Ich möchte genau das weiter optimieren, um weitere FPS rauszukitzeln. Das Image liegt als Byte Array im Speicher und soll in jedem Frame verändert werden. Die entsprechenden Methoden sind so "ausgereift" dass ich da prozentual keine Steigerung mehr sehe und auch erstmal nicht möchte. Sie sind schlicht weg schnell genug für mich.

Das Ganze hat keinerlei Hintergrund, sondern mir geht es nur um das technisch machbare. Ich möchte nicht mit Managed DirectX, Hardwarebeschleunigung, WPF usw umgehen. Am Besten ist es, wenn das Ganze ohne jegliche Win API Zugriffe auskäme und unter .Net 2.0 lauffähig wäre. Unsicherer Code wäre auch möglich und wird teilweise verwendet. Abweichend von meinen Auflagen habe ich mit BitBlt experimentiert, mit dem Ergebnis dass ich entweder ein schwarzes Bild mit ca. 80 FPS habe oder das Ergebnis mit der Vorlage übereinstimmt aber dann die Framerate einbricht und ich dann bei 1 FPS lande bzw. alles stehen bleibt.

Kurz zusammgefasst: Wie kann ich so schnell wie möglich ein sich ständig veränderndes Bitmap unter Verwendung der .Net 2.0 Funktionalitäten zeichnen?

Hier noch den aktuell schnellsten Code den ich habe:

Code:
    // Felder in der Klasse mit der Initialisierung (passiert eigentlich in einer ResizeBuffer Methode)
    IntPtr ptrBuffer = Marshal.AllocHGlobal(1280 * 1024 * 4);
    Bitmap bmpFrame = new Bitmap(1280, 1024, 1280 * 4, PixelFormat.Format32bppArgb, ptrBuffer);
    Graphics surface = this.CreateGraphics();
    BufferedGraphics graphBuffer = BufferedGraphicsManager.Current.Allocate(surface, new Rectangle(0, 0, 1280, 1024));

    // Mein Sorgenkind:
    public void Render()
    {
      graphics.DrawImage(bmpFrame, 0, 0); // -> 72,88% der Zeit gehen hier drauf
      post_processing(graphics); // -> 0.61 % der Zeit, uninteressant und nicht das Thema(!)
      graphBuffer.Render(surface); // -> 25.9% der Zeit, uninteressant und nicht das Thema(!)
    }

Die Initialisierung erfolgt dynamisch in Abhängigkeit von den Screen-Einstellungen. Ich habe sie für das obige Beispiel durch die aktuelle Config ersetzt. Also wer kann mir da vielleicht einen oder mehrere Tipps geben?

Nun danke ich dir speziell, dass du dir die Zeit genommen hast, das Ganze einmal durchzulesen.

Also bis dann.
Rossibaer
 
Was willst du da noch großartig rausholen?

Wenn DrawImage von der Graphics Klasse der Flaschenhals ist, wird dir nichts weiter übrig bleiben als ne eigene DrawImage Methode zu schreiben.
 
Vlt. soltle man einfach die arbeit vom Prozessor auf die Grafikkarte verlagern, die ist immerhin für solche aufgaben gedacht.

Allerdings weiß ich nicht in wie fern -.net sowas ohne externe libs kann.....
 
@toeffi: Zuerst musste ich ein wenig schmunzeln. Ist es nicht der Reiz mal eine Grenze zu sprengen und etwas weiter zu gehen?

Aber nun zu deiner Idee, eine eigene DrawImage Methode würde ich sehr gerne schreiben, wenn ich wüßte wie ich die Daten des Bitmaps, die ich bis ins letzte Bit kenne nun schnell genug ins Graphics Objekt reinpumpen kann.

Ein anderer Ansatz wäre, dass ich vermutlich nicht exakt das gleiche Bitmap Format habe wie es z.B. vom Screen verwendet wird und die DrawImage Methode nun mit Konvertierung ausgebremst wird. Wie kann ich da Änderungen vornehmen?

Die Render Methode von BufferedGraphics verwendet intern das BitBlt, was auch sehr schnell ist, wie kann ich das verwenden um das Bitmap ins Graphics Objekt reinzuverwerfen? Oder gar den Zwischenschritt weglassen und direkt auf den Screen blitten? Wenn ich im Netz suche bekomme ich immer wieder die Anwendung von BitBlt um einen Screenshot ins Bitmap zu saugen, jedoch nirgends den umgekehrten Weg, der definitv nicht so ohne weiteres (durch Tauschen der Parameter) bewerkstelligt werden kann. Siehe meine ersten Ergebnisse oben.

@Mercsen: Das mit der Grafikkarte ist klar eine Möglichkeit. Jedoch ist bei .Net 2.0 keine Unterstützung nativ dabei, zumindest habe ich nix in dieser Richtung gefunden. Mit der WPF könnte es evtl. möglich sein, die wurde aber erst mit einem späteren Framework 3.5(?) oder 4.0 eingeführt und steht somit für mich noch nicht zur Verfügung. Desweiteren wäre es mir lieb gänzlich ohne externe Libs auszukommen.


Allgemein: Ich weiß selber, dass ich mich hiermit an den Grenzen befinde, aber das ist gerade so reizvoll für mich.

Danke für eure Aufmerksamkeit!

Grüße
Rossibaer
 
Hehe, ja klar ist es interessant die Grenzen auszureizen.

Also ich denke mal du hast die Grenzen vom .NET Framework erreicht. Alle weiteren Optimierungen würden auf die WIN Api zurückfallen oder gar natives C++

Was ich dir für die DrawImage-Methode noch empfehlen kann: Schau doch mal mit einem Reflector deiner Wahl im Code nach wie die da vorgehen, eventuell kannst du das Bitmap noch etwas "optimierter" an die DrawImage-Methode übergeben.

Mehr fällt mir leider nicht mehr ein.
 
Für die, die es interessiert:

Die Graphics.DrawImage Methode wird etwas schneller, wenn man die Properties noch etwas anpasst:

Code:
Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;

das hatte bei mir nochmal zusätzliche 4 bis 5 FPS gebracht. Viel mehr scheint wirklich nicht mehr zu gehen.

Ich habe aber nun auch mal die Win API verwendet (BitBlt, SelectObject, DeleteObject und GetObject Funktionen aus der GDI32.DLL) und komme nun auf ca. 100 FPS. Aber auch da scheints noch weiter zu gehen.
Die Schattenseite ist, dass mein Bild nun spiegelverkehrt dargestellt wird. :D Aber das sollte auch lösbar sein.

Andererseits werde ich mal StretchDIBits ausprobieren, welche angeblich hardwarebeschleunigt arbeiten soll, wenn man dem glauben kann, was man so im Netz findet.
 
Zuletzt bearbeitet:
Der Grund für die langsame Kopieroperation ist zum einen C#, und zum anderen das Konzept dahinter. Was hier eigentlich gemacht wird ist ein BitBlt, und für genau diese Operation bieten alle Grafikkarten Beschleunigerfunktionen an, eben weil die Operation so langsam ist. BitBlt ist einer der Hauptgründe warum 2D-Grafikdarstellung ohne Grafiktreiber (also SW-Rasterizer) so langsam ist.

Wenn du wirklich schnell kopieren willst dann verwende Direct2D oder gleich Direct3D. GDI ist übrigens zum größten Teil _nicht_ hardwarebeschleunigt!
 
@IceMatrix: Zuerst einmal Danke für deine Anteilnahme, ABER

1. War es mein Ziel etwas zu machen, was eben nicht auf native API, DirectX oder sonstigen Gedöns außerhalb des .Net Frameworks aufbaut. Just for fun, mal sehen was geht - ist die Devise! Aber ein aufmerksamer Leser hätte das auch schon aus dem Startpost entnehmen können. ;)

2. DrawImage und BitBlt sind zwei verschiedene Sachen oder hast du den Code von GdipDrawImageI aus der gdiplus.dll reverse engineered ?!? :)

3.
Der Grund für die langsame Kopieroperation ist zum einen C#, und zum anderen das Konzept dahinter
Was willst du mir damit sagen?

4. BitBlt und langsam? Ab 25 FPS wirds ein Film und bei 100FPS kann ich nun wirklich nicht meckern. Zumal mein Rechner nicht gerade der Hirsch ist.

5.
GDI ist übrigens zum größten Teil _nicht_ hardwarebeschleunigt!
Habe ich jemals etwas anderes behauptet? :D

---------------------------------------------------------------------------

Neben dem Thema, aber weil die Frage auf kam, hier für alle die es interessiert:

Wie habe ich die Dauer des Aufrufs der Methoden gemessen?

Im VS 2005 gibts das soweit ich weiß nicht, jedoch hat da das .Net Framework ab 2.0 eine System.Diagnostics.Stopwatch Klasse, die ich verwendete um einen "kleinen Performance-Monitor" zu schreiben. Intern verwendet Stopwatch die QueryPerformanceCounter API Funktion die ideal für solche Sachen gemacht ist. Vom Grundprinzip ist das so, dass der PerformanceCounter die Anzahl von Ticks zählt. Desweiteren hat der PerformanceCounter eine Frequenz die angibt, wieviele Ticks innerhalb einer Sekunde gezählt werden.

Also habe ich folgendes gemacht:

1. Vor dem Aufruf des Code-Abschnitts (z.B. eine Methode) ermittelt man die Ticks und schreibt sie sich in eine Variable, z.B.
Code:
long startCount = Stopwatch.GetTimestamp();

2. Man führt den Codeabschnitt/Methode aus

3. Nach dem Aufruf ermittelt man die Ticks und verrechnet sie mit dem Startwert, z.B.
Code:
long duration = Stopwatch.GetTimestamp() - startCount;

In duration hast du nun die genaue Anzahl der Ticks für das Ausführen der Methode. Mit Stopwatch.Frequency kannst du das Ganze hochrechnen auf die Sekunde, d.h. wieviele Male deine Methode pro Sekunde ausgeführt werden kann, z.B.
Code:
decimal calls_per_sec = (decimal)duration / (decimal)Stopwatch.Frequency;

Das ist so das Grundprinzip. Ich habe mir daraus eine kleine Klasse geschrieben, die dann 5 Methoden enthielt:
Code:
class PerformanceMonitor
{
  public static void StartAll(); // Start der gesamten Messung
  public static void Start(string entry); // Start einer einzelnen Messung, entry wird zur Zuordnung der Werte mittels Dictionary verwendet
  public static void Stop(string entry); // Ende einer einzelnen Messung
  public static void StopAll(); // Ende der gesamten Messung
  public static void WriteDebugOutput(); // Ausgabe aller gemessenen Werte mit Verrechnung, z.B. Durchschnitt, Summe in sec, %, ticks
}

Die Messung habe ich dann in meinem Code so gemacht:

Code:
private void EngineRender() // Aufruf in einer Loop
{
  PerformanceMonitor.StartAll();

  PerformanceMonitor.Start("DrawImage");
  graphics.DrawImage(bmpFrame, 0, 0);
  PerformanceMonitor.Stop("DrawImage");

  PerformanceMonitor.Start("PostProcess");
  PostProcess(graphics);
  PerformanceMonitor.Stop("PostProcess");

  PerformanceMonitor.StopAll();
}

private void EngineStop() // wird bei Beendigung des Programms ausgeführt
{
  PerformanceMonitor.WriteDebugOutput();
}

Das wäre nun eine Möglichkeit um an Daten über die Ausführungsgeschwindigkeit des Codes zu kommen. Es gibt auch eine ganze Reihe von Profilern, die diese Sachen von Haus aus beherrschen und weitaus mehr machen. Für mich hat das aber vollkommen gereicht.

Also viel Spaß damit...
Rossibaer

PS: Hier noch ne Info an diejenigen die sowieso alles besser wissen:
Und ja ich weiß, die Stopwatch hat selber schon ne ganze Menge an nützlichen Methoden bereitgestellt. Sicher hätte ich mir das Ganze sparen können. Das ist aber nicht mein privates Ziel!
 
Zuletzt bearbeitet:
Rossibaer schrieb:
1. War es mein Ziel etwas zu machen, was eben nicht auf native API, DirectX oder sonstigen Gedöns außerhalb des .Net Frameworks aufbaut. Just for fun, mal sehen was geht - ist die Devise! Aber ein aufmerksamer Leser hätte das auch schon aus dem Startpost entnehmen können. ;)
GDI+ ist native API. Ob du jetzt Direct2D oder GDI+ verwendest macht da gar keinen Unterschied. Wenn du selbst rendern willst, dann implementiere _alle_ Algorithmen selbst und verwende die native API nur für den Zugriff auf den Frame Buffer wenn das fertige Bild auf dem Bildschirm dargestellt werden soll. Für alles andere brauchst du gar keine API!


Rossibaer schrieb:
2. DrawImage und BitBlt sind zwei verschiedene Sachen oder hast du den Code von GdipDrawImageI aus der gdiplus.dll reverse engineered ?!? :)
Es gibt einen Unterschied zwischen der Api BitBlt() und dem "Verfahren" dahinter (Bit Blit). Und ein Bild in ein anderes kopieren ist genau Bit Blit, egal wie es hier konkret genannt wird.
-> http://en.wikipedia.org/wiki/Bit_blit

Rossibaer schrieb:
3. Was willst du mir damit sagen?
C# an sich ist lahm. Die Kopieroperation ist hier zwar in C implementiert, aber kopieren ist keine "billige Operation", v.a. wenn die Bilder groß sind. Deswegen wird diese Operation immer hardwarebeschleunigt.

Rossibaer schrieb:
4. BitBlt und langsam? Ab 25 FPS wirds ein Film und bei 100FPS kann ich nun wirklich nicht meckern. Zumal mein Rechner nicht gerade der Hirsch ist.
25 FPS ist Diashow! Spiel mal ein 3D-Spiel damit, dann weißt du was ich meine.
100 FPS sind auch kein super Wunder. Mit der "richtigen" API machst du >>1000 FPS.

Rossibaer schrieb:
5. Habe ich jemals etwas anderes behauptet? :D
However.
 
Hi IceMatrix,

danke erstmal für deine Antwort. Es tut gut, mal wieder einen ganz anderen Standpunkt zu hören...

Ja, ich bin dabei mir das alles selbst zu schreiben. Warum? Ich habe viel Zeit, Langeweile und eine riesen Neugier mal was ganz anderes als diesen üblichen DBMS, SQL, TextBox hier, Combobox da, Form dort - Glumbatsch zu programmieren.

Im übrigen den Rasterizer für die vielen noch kommenden Dreiecke habe ich schon fertig und der läuft erstmal ganz gut, d.h. ich mach es in .Net ohne API. Einfach nur native Typen wie long, byte, int etc. und fertig. Solange wie ich Graphics.DrawImage verwende, bin ich immer noch in der .Net Welt ohne native API. Das GDI+ im Hintergrund von .Net verwendet wird, interessiert mich überhaupt nicht, da bei Mono das ganze dann sowieso anders implementiert ist...

Was ich halt gesucht habe, war ein Weg mein fertiges Byte-Array schnellstmöglich auf den Desktop zu feuern. Wie die Bytes angeordnet sein müssen um das Bild zu sehen, ist nicht das Problem, da ich das Format meiner Daten entsprechend flexibel anpassen kann. Also wenn einer den Zauber-IntPtr zum Framebuffer kennt und mir zeigt, wo ich drauf achten muss, dann bitte her damit... ;)

Ach noch was, die Diskussion um 25 FPS und Diashow ist echt müsig. Das menschliche Auge kann ab 25 Bildern / s nicht mehr unterscheiden, ob es sich um einzelne Bilder oder nen Film dreht. Ich bin da etwas _naiv_ und gehe davon aus, dass die wahrgenommenen Ruckler eher von einer geringen Zeitdifferenz der Anzeige pro Bild kommen. Nehme ich also mal an, dass ich es schaffen könnte konstant 25 oder gar 30 Bilder im exakt gleichen Zeitraum von einer Sekunde zu präsentieren, dann dürfte es theoretisch kein Problem sein.

So die Theorie, bis zur Praxis ist es noch ein weiter steiniger Weg und sicher werde ich _grandios_ scheitern, alles wieder gefrustet in den Bithimmel schiessen und mich anderen Dingen zuwenden. Egal! Wie gesagt, ich habe Zeit, Langeweile und etwas das mich momentan sehr interessiert... :)

Grüße
Rossibaer
 
So nach längerem Testen und Rumprobieren, habe ich mich, wie zu erwarten war, für API Funktionen entschieden um die Bilddaten auf den Bildschirm zu zeichnen.

Code:
    [StructLayout(LayoutKind.Sequential)]
    unsafe public struct BITMAPINFO
    {
      public int biSize;
      public int biWidth;
      public int biHeight;
      public short biPlanes;
      public short biBitCount;
      public int biCompression;
      public int biSizeImage;
      public int biXPelsPerMeter;
      public int biYPelsPerMeter;
      public int biClrUsed;
      public int biClrImportant;
      public fixed uint bmiColors[1];
    }

    [DllImport("gdi32.dll"), System.Security.SuppressUnmanagedCodeSecurity()]
    unsafe public static extern int SetDIBitsToDevice(
      HandleRef hdc,      // handle to DC
      int XDest,          // x-coord of destination upper-left corner
      int YDest,          // y-coord of destination upper-left corner 
      int dwWidth,        // source rectangle width
      int dwHeight,       // source rectangle height
      int XSrc,           // x-coord of source lower-left corner
      int YSrc,           // y-coord of source lower-left corner
      int uStartScan,     // first scan line in array
      int cScanLines,     // number of scan lines
      HandleRef lpvBits,  // array of DIB bits
      BITMAPINFO* lpbmi,  // bitmap information
      uint fuColorUse     // RGB or palette indexes
    );

    public const uint DIB_RGB_COLORS = 0;
    public const int BI_RGB = 0;

    [DllImport("kernel32.dll", EntryPoint = "RtlZeroMemory", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true), System.Security.SuppressUnmanagedCodeSecurity()]
    public static extern void ZeroMemory(HandleRef destData, int size);

    unsafe private void CreateBuffer()
    {        
      this.ptrFrameData = Marshal.AllocHGlobal(this.surface_size);
      this.hrefFrameData = new HandleRef(null, this.ptrFrameData);
      this.hFrameData = (uint*)this.ptrFrameData;

      this.ptrBmpInfo = Marshal.AllocHGlobal(sizeof(WinAPI.BITMAPINFO));
      ZeroMemory(new HandleRef(null, this.ptrBmpInfo), sizeof(BITMAPINFO));
      hBmpInfo = (BITMAPINFO*)this.ptrBmpInfo;
      (*hBmpInfo).biSize = sizeof(BITMAPINFO);
      (*hBmpInfo).biWidth = this.surface_width;
      (*hBmpInfo).biHeight = -this.surface_height; // negative value means Top-Down-Bitmap instead of Bottom-Up-Bitmap
      (*hBmpInfo).biPlanes = 1;
      (*hBmpInfo).biBitCount = 32;
      (*hBmpInfo).biCompression = BI_RGB;
      (*hBmpInfo).biSizeImage = this.surface_size;
      (*hBmpInfo).biXPelsPerMeter = 0;
      (*hBmpInfo).biYPelsPerMeter = 0;
      (*hBmpInfo).biClrUsed = 0;
      (*hBmpInfo).biClrImportant = 0;
    }

    unsafe private void Present()
    {
      IntPtr hdc = this.graphSurface.GetHdc();
      SetDIBitsToDevice(new HandleRef(this.graphSurface, hdc), 0, 0, surface_width, surface_height, 0, 0, 0, surface_height, hrefFrameData, hBmpInfo, DIB_RGB_COLORS);
      this.graphSurface.ReleaseHdc(hdc);
    }

Das Bild selbst ist ein Array aus Breite * Höhe * 4 Bytes, jedes Pixel besteht aus 4 Byte (RGBA) wobei der Alphaanteil im DIB (=Device Independent Bitmap) nicht genutzt wird...

Das Ergebnis war das meine App nun bei gleichem Bild und Dreieck knapp 200 FPS erreichte. Sobald ich aber anfing weitere Dreiecke zu zeichnen, gings rasant nach unten. Aber das ist ja auch schön so, da habe ich noch viel zum ausprobieren... :D Bin eh erstmal mit der Rendering Pipeline beschäftigt...
 
Zuletzt bearbeitet:
Sehr interessantes Projekt welches du das verfolgst. Einen Einblick in den Code willst du mir/uns sicher nicht geben ? Bzw. eine kompilierte Version waer auch schon ein Anfang.
 
Hi toxn,
zur Zeit ist es noch völlig sinnlos den Code zu posten, aber sollte ich das tatsächlich bis zum Ende durchziehen, dann werde ich sicherlich das mal als Open Source veröffentlichen. Jetzt ist es aber noch so, dass ich nicht weiß, ob ich überhaupt zum Ziel komme oder nicht, sondern einfach nur an den Basics rumbastel. Nen Kollege hat auch schon Interesse angemeldet um die "Engine" für seine kleine Simulation zu verwenden. Das gibt für mich somit einen Anreiz. Aber bis es soweit ist, wird sicher noch viel Zeit vergehen. Komme zur Zeit nur am Wochenende dazu, was zu machen...

Eine kompilierte Version zu veröffentlichen, halte ich für weniger sinnvoll, da man nur ein Foto und ein rotes Dreieck sieht, welches immer wieder neu auf den Bildschirm gezeichnet wird. Aber abwarten und Tee trinken. Vielleicht wirds was.
 
Und wieder ein Code Snippet für diejenigen, die es interessiert:

Code:
  public struct Color
  {
    public byte R, G, B;

    static public implicit operator int(Color value)
    {
      return (int)((0xFF << 24 | value.R << 16 | value.G << 8 | value.B));
    }

    static public implicit operator Color(int value)
    {
      Color color;
      color.R = (byte)((value & 0x00FF0000) >> 16);
      color.G = (byte)((value & 0x0000FF00) >> 8);
      color.B = (byte)(value & 0x000000FF);
      return color;
    }

    static public readonly Color Red = (Color)(0x00FF0000);
    static public readonly Color Green = (Color)(0x0000FF00);
    static public readonly Color Blue = (Color)(0x000000FF);
    static public readonly Color Black = (Color)(0x00000000);
    static public readonly Color White = (Color)(0x00FFFFFF);
  }

  public partial class Surface
  {

    unsafe struct FillStruct
    {
      public fixed long data[128];
    }

    unsafe public void Clear(Color color)
    {
      FillStruct colors = new FillStruct();
      int c = color;
      int* fill = (int*)&colors;
      for (int indx = 0; indx < sizeof(FillStruct) / 4; indx++) *(fill++) = c;
      FillMemory((FillStruct*)this.ptrFrameData, this.surface_size, colors);
    }

    unsafe private void ZeroMemory(FillStruct* buffer, int size_in_bytes)
    {
      FillMemory(buffer, size_in_bytes, new FillStruct());
    }

    unsafe private void FillMemory(FillStruct* buffer, int size_in_bytes, FillStruct data)
    {
      for (int size = size_in_bytes / sizeof(FillStruct); size > 0; --size) *(buffer++) = data;
      byte* rest_buffer = (byte*)buffer;
      byte* rest_data = (byte*)&data;
      for (int size = size_in_bytes % sizeof(FillStruct); size > 0; --size) *(rest_buffer++) = *(rest_data++);
    }

  }

Am Anfang eines Renderdurchgangs wird immer ein Clear() der Zeichenfläche durchgeführt, sodaß vom vorhergehenden Frame keine Artefakte übrig bleiben. Den oben gezeigten Code verwende ich um genau das zu machen. Das hat den Vorteil, dass ich eine WinAPI Funktion und genauer die RtlZeroMemory Funktion aus der Kernel32.dll entfernen konnte, da mein Code sogar geringfügig schneller läuft (also weniger API mehr .Net) und außerdem als großen Bonus noch jede beliebige RGB Farbe für den Hintergrund wählen kann.

Viel Spaß damit...
Rossibaer
 
Zurück
Oben