2016-01-28 6 views
6

Win32-Bitmaps sind (viel) schneller zu zeichnen als SetPixelV oder eine andere Funktion wie. Wie funktioniert das, wenn der Computer am Ende Pixel für die Bitmap zeichnet?Wie ist Win32 Bitmap-Rendering schneller als Pixel?

+2

'SetPixelV' verursacht viel Funktionsaufruf, um ein einzelnes Pixel zu zeichnen. –

+1

[BitBlt] (https://msdn.microsoft.com/en-us/library/dd183370.aspx) ist normalerweise hardwarebeschleunigt, wobei die CPU lediglich ein paar Befehle an die Hardware ausgeben muss, die die Blockübertragung von ausführt Erinnerung. – IInspectable

+1

Im Allgemeinen erfolgt eine schnelle Grafikaktualisierung durch das Kopieren großer Pixelblöcke auf einmal; häufig unter Verwendung von Hardware, die speziell dafür entwickelt wurde. – mah

Antwort

5

Angenommen, Sie haben ein Pixel. Dieses Pixel hat die Farbkomponenten A B und C. Die zu zeichnende Oberfläche hat die Farbkomponenten X Y und Z.

Zuerst müssen Sie überprüfen, ob sie übereinstimmen. Wenn sie nicht übereinstimmen, steigen die Kosten. Angenommen, sie stimmen überein.

Als nächstes müssen Sie Grenzen überprüfen - hat der Anrufer Ihnen etwas dummes gegeben? Einige Vergleiche, Additionen und Multiplikationen.

Als nächstes müssen Sie herausfinden, wo das Pixel ist. Dies sind einige der Multiplikationen und Additionen.

Nun müssen Sie auf die Quelldaten und die Zieldaten zugreifen und diese schreiben.


Wenn Sie eine Scanlinie zu einem Zeitpunkt arbeiten, fast alle dieser Overhead oben kann einmal durchgeführt werden. Sie können berechnen, welcher Teil der Scanline in Grenzen fällt oder nicht, mit nur etwas mehr Overhead als mit einem Pixel. Sie können feststellen, wo der Scanline in das Ziel schreibt mit nur ein bisschen mehr Overhead als ein Pixel. Sie können Farbraumkonvertierungen mit demselben Overhead wie ein Pixel überprüfen.

Der große Unterschied ist, dass Sie, anstatt ein Pixel zu kopieren, in einen Block kopieren.

Wie es passiert, sind Computer wirklich gut darin, Blöcke von Dingen zu kopieren. Es gibt eingebaute Anweisungen für einige CPUs, einige Speichersysteme können dies tun, ohne dass die CPU beteiligt ist (CPU sagt "Kopiere X nach Y", kann dann andere Dinge tun, und die Speicher-zu-Speicher-Bandbreite ist möglicherweise höher als die Speicher- zu-CPU-zu-Speicher). Auch wenn Sie durch die CPU rutschen, gibt es SIMD-Anweisungen, mit denen Sie an 2, 4, 8, 16 oder sogar mehr Dateneinheiten gleichzeitig arbeiten können, solange Sie mit ihnen auf die gleiche Weise arbeiten ein begrenzter Befehlssatz

In einigen Fällen können Sie sogar Arbeit auf die GPU verlagern - wenn sowohl Quelle und Ziel Scanline auf der GPU sind, können Sie sagen "yo GPU, Sie behandeln", und die GPU ist noch spezieller dafür spezialisiert diese Art von Aufgabe.

Die allererste Optimierung - nur einmal pro Scanlinie statt einmal pro Pixel - kann Ihnen leicht eine 2x bis ~ 10x Beschleunigung geben. Die zweite - effizientere Blitting - weitere 4x bis ~ 20x schneller. Alles auf der GPU kann ~ 2x bis 100x schneller sein.

Die letzte Sache ist der Overhead des tatsächlichen Aufrufs der Funktion. Normalerweise ist das nicht wichtig. aber wenn SetPixel 1 Million Mal aufgerufen wird (ein 1000 x 1000-Bild oder ein Bildschirm von bescheidener Größe), addiert es sich.

Für ein HD-Display mit 2 Millionen Pixeln werden 60 Mal pro Sekunde 120 Millionen Pixel pro Sekunde manipuliert. Ein Single-Threaded-Programm auf einem 3-GHz-Rechner bietet nur Platz für ca. 25 Anweisungen pro Pixel, wenn Sie mit dem Bildschirm Schritt halten wollen und davon ausgehen, dass nichts anderes passiert (was unwahrscheinlich ist). Auf einem 4k-Monitor sind Sie auf 6 Anweisungen pro Pixel beschränkt.

Mit diesen vielen Pixeln, mit denen gespielt wird, kann jede Anweisung, die Sie machen können, abgeschabt werden, was einen großen Unterschied macht.


Multiplikatoren aus dem Nichts gezogen. Ich habe einige Umwandlungen von pro-Pixel-Operationen in per-scanline-Operationen geschrieben, die jedoch beeindruckende Beschleunigungen gezeigt haben, sowie dito für CPU-zu-GPU-Lasten, und SIMD hat beeindruckende Geschwindigkeitszuwächse gezeigt.

2

Wiederholte Aufrufe an eine Funktion wie SetPixelV sind langsam, weil sie jedes Mal eine Koordinate in einen Speicheroffset übersetzen müssen und möglicherweise auch eine Farbübersetzung im laufenden Betrieb ausführt.

Ein einfaches „Set Pixel“ -Funktion wie folgt aus (ohne Grenzen-Tests, Farbe Übersetzung oder etwas Phantasie) aussehen könnte:

size_t offset = y * bytes_per_scanline + x * bytes_per_pixel; 
for(size_t i = offset; i < offset + bytes_per_pixel; i++) 
    target[i] = source[i]; 

Bitmaps, auf der anderen Seite, werden über einen Prozess im Allgemeinen gezogen bekannt als blitting. Dies ist im Wesentlichen eine direkte Kopie von einem Speicherort zu einem anderen. Um dies unter Windows zu erreichen, erstellen Sie einen Gerätekontext für Ihr Bitmap, der kompatibel mit dem Zielkontext ist. Damit wird sichergestellt, dass der Speicher ohne Übersetzung kopiert werden kann. Es kann auch hardwarebeschleunigte Kopien bereitstellen, die noch schneller sind.

Ein einfaches „Kopieren“ blit könnte wie folgt aussehen:

size_t nbytes = bytes_per_scanline * height; 
for(size_t i = 0; i < nbytes; i++) 
    target[i] = source[i]; 

Dies beinhaltet keine Koordinaten Lookups und wird in Bezug auf Speicher-Cache zugreift, sehr effizient sein. Es gibt viel schnellere Möglichkeiten, Speicherbereiche zu kopieren, und das obige Beispiel soll es nur illustrieren.

+0

Entschuldigung, wenn es ein bisschen spät ist und wenn das Thema nicht stimmt, aber was meinst du mit "Es gibt viel schnellere Möglichkeiten, um Speicherstücke zu kopieren, und das obige Beispiel ist einfach zu illustrieren."? Kannst du mir eins von ihnen geben? Ich werde bald auf andere Plattformen umziehen und muss sie daher vielleicht selbst implementieren. –

+0

Dieses Kopierschleifenbeispiel kopiert jeweils ein Byte. Kann der Compiler zur Kompilierzeit keine Größengarantien feststellen oder zur Laufzeit keine alternativen Code-Pfade festlegen, wird es eine beschissene Schleife. Eine bessere Optimierung besteht darin, in Blöcke zu kopieren. Dann gibt es weniger Schleifenzählung und mehr tatsächliches Kopieren. Vektor-Technologien wie MMX, SSE und AVX bieten größere Registergrößen (64-Bit, 128-Bit, 256-Bit, 512-Bit) und ermöglichen ein schnelleres Kopieren. Kombiniert mit Loop-Abrollung können Sie eine höhere Leistung erzielen. All dies hängt davon ab, was Sie eigentlich über Ihre Daten wissen (oder garantieren können). – paddy