Schnelle Methode zum Kopieren des Speichers mit Übersetzung – ARGB nach BGR

Lesezeit: 5 Minuten

Benutzeravatar von Adam Davis
Adam Davis

Überblick

Ich habe einen Bildpuffer, den ich in ein anderes Format konvertieren muss. Der Ursprungsbildpuffer besteht aus vier Kanälen, 8 Bit pro Kanal, Alpha, Rot, Grün und Blau. Der Zielpuffer besteht aus drei Kanälen, 8 Bit pro Kanal, Blau, Grün und Rot.

Die Brute-Force-Methode lautet also:

// Assume a 32 x 32 pixel image
#define IMAGESIZE (32*32)

typedef struct{ UInt8 Alpha; UInt8 Red; UInt8 Green; UInt8 Blue; } ARGB;
typedef struct{ UInt8 Blue; UInt8 Green; UInt8 Red; } BGR;

ARGB orig[IMAGESIZE];
BGR  dest[IMAGESIZE];

for(x = 0; x < IMAGESIZE; x++)
{
     dest[x].Red = orig[x].Red;
     dest[x].Green = orig[x].Green;
     dest[x].Blue = orig[x].Blue;
}

Allerdings brauche ich mehr Geschwindigkeit, als eine Schleife und drei Byte-Kopien bieten. Ich hoffe, es gibt ein paar Tricks, mit denen ich die Anzahl der Lese- und Schreibvorgänge im Speicher reduzieren kann, da ich auf einem 32-Bit-Computer laufe.

zusätzliche Information

Jedes Bild ist ein Vielfaches von mindestens 4 Pixeln. Wir könnten also 16 ARGB-Bytes adressieren und sie in 12 RGB-Bytes pro Schleife verschieben. Vielleicht kann diese Tatsache genutzt werden, um die Dinge zu beschleunigen, zumal sie schön in 32-Bit-Grenzen fällt.

Ich habe Zugriff auf OpenCL – und während dies das Verschieben des gesamten Puffers in den GPU-Speicher und das anschließende Verschieben des Ergebnisses wieder hinaus erfordert, sind die Tatsache, dass OpenCL gleichzeitig an vielen Teilen des Bildes arbeiten kann, und die Tatsache, dass große Speicherblockbewegungen tatsächlich erfolgen ziemlich effizient kann dies zu einer lohnenden Erkundung machen.

Während ich oben das Beispiel kleiner Puffer gegeben habe, verschiebe ich wirklich HD-Video (1920 x 1080) und manchmal größere, meistens kleinere Puffer, so dass eine 32 x 32-Situation trivial sein mag, das Kopieren von 8,3 MB Bilddaten Byte für Byte ist es jedoch wirklich, wirklich schlecht.

Auf Intel-Prozessoren (Core 2 und höher) ausgeführt, und daher gibt es Streaming- und Datenverarbeitungsbefehle, von denen ich weiß, dass sie existieren, von denen ich aber nichts weiß – vielleicht wären Hinweise darauf, wo Sie nach speziellen Anweisungen zur Datenverarbeitung suchen sollten, gut.

Dies geht in eine OS X-Anwendung, und ich verwende XCode 4. Wenn die Assemblierung schmerzlos und der offensichtliche Weg ist, kann ich diesen Weg gehen, aber da ich es bei diesem Setup noch nicht getan habe, bin ich vorsichtig zu viel Zeit darin versinken.

Pseudocode ist in Ordnung – ich suche keine vollständige Lösung, nur den Algorithmus und eine Erklärung für alle Tricks, die möglicherweise nicht sofort klar sind.

  • richtet der Compiler BGR an Dword aus?

    – Marinara

    24. Juli 2011 um 1:03 Uhr

  • @marinara Nein, es ist Byte-ausgerichtet.

    – Adam Davis

    24. Juli 2011 um 1:11 Uhr

  • Es sollte keinen Sinn machen, die GPU dafür zu verwenden, es sei denn, die Daten kommen von dort in das System. Sie sollten in der Lage sein, den Speicherbus mit der CPU zu sättigen.

    – Stephan Eggermont

    16. August 2011 um 15:46 Uhr

  • Ich habe mit niemandes Code gespielt, aber AFAICT hat niemand die Möglichkeit des Äquivalents von erwähnt for(x = 0; x < IMAGESIZE; x++) { dest[x].Red = orig[x].Red; } for(x = 0; x < IMAGESIZE; x++) { dest[x].Green = orig[x].Green; } for(x = 0; x < IMAGESIZE; x++) { dest[x].Blue = orig[x].Blue; }. Überholen in diesem Fall die einfacheren Loops das Bit Twiddling?

    – Mark Hurd

    24. Januar 2015 um 13:01 Uhr

  • Mich würde interessieren, wie neuere Versionen von GCC funktionieren. Einige der zwischen 4.2 und 4.6 eingeführten Optimierungen sind beeindruckend. Könnten Sie auch die Standardabweichung für diese Zeiten berechnen?

    – liori

    24. Juli 2011 um 12:22 Uhr


  • @liori Ich habe weitere Daten hinzugefügt, einschließlich der Standardabweichung. Tut mir leid, aber ich habe gerade keine neuere Version als 4.2.1. Ich werde in Zukunft aktualisieren, nachdem ich eine neuere Version erhalten habe.

    – ughoavgfhw

    24. Juli 2011 um 17:11 Uhr

  • @MrE Keine dumme Frage. Ich habe einen Datensatz für den mitgelieferten Code hinzugefügt, und es hat ungefähr doppelt so lange gedauert pshufb.

    – ughoavgfhw

    28. Juli 2011 um 19:45 Uhr

  • @ughoavgfhw hat gezeigt, dass es hauptsächlich speichergebunden ist. Es wäre interessant, mit explizitem Prefetch in einer dieser Schleifen zu experimentieren, um zu sehen, ob das hilft.

    – Ben Jackson

    29. Juli 2011 um 20:30 Uhr

  • @Camilo Der Compiler kann den C-Code optimieren, aber nicht die Inline-Assembly, sodass die Assembly-Version möglicherweise unnötige Auffüllungen aufweist, z. B. das Speichern nicht verwendeter Register. Die Differenz zwischen beiden ist kleiner als die Standardabweichung, könnte also auch durch äußere Einflüsse verursacht werden.

    – ughoavgfhw

    17. Januar 2012 um 18:30 Uhr

  • +1 Dies ist mit ziemlicher Sicherheit optimal. Es kann jedoch möglich sein, den Compiler dazu zu bringen, denselben oder ähnlichen Code zu generieren, ohne nicht portierbare intrinsische Elemente zu verwenden …

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. Juli 2011 um 2:55 Uhr

  • Eine Erklärung der magischen Zahlen für _mm_set_epi8 wäre wünschenswert.

    – entschleunigter Kaviar

    28. Juli 2011 um 3:30 Uhr

  • @Daniel, schau dir meine Antwort an.

    – MSN

    28. Juli 2011 um 3:52 Uhr

  • Besteht die Möglichkeit, dass Sie die Shuffles für BGRA zu RGB bereitstellen können? Ich kann mir nicht vorstellen, wie das alles funktioniert.

    – Geoffrey

    16. November 2017 um 10:54 Uhr

  • Duff’s Device ist nur eine seltsame C-spezifische Art, eine Schleife aufzurollen. Es braucht mehr als das, um eine wirklich gute Leistung zu erzielen.

    Benutzer149341

    24. Juli 2011 um 2:41 Uhr

  • Mein C und Assembly ist etwas eingerostet, aber eine Schleife aufzurollen ist besser als nichts, wenn Sie alles mit der CPU verschieben müssen.

    – Mikromega

    24. Juli 2011 um 2:49 Uhr


  • @R: Ich bin kein erfahrener C-Programmierer. Ich entwerfe Webanwendungen. Könnten Sie das bitte erklären? Was ist so lustig?

    – Mikromega

    28. Juli 2011 um 8:18 Uhr

  • Duff’s Device ist nur eine seltsame C-spezifische Art, eine Schleife aufzurollen. Es braucht mehr als das, um eine wirklich gute Leistung zu erzielen.

    Benutzer149341

    24. Juli 2011 um 2:41 Uhr

  • Mein C und Assembly ist etwas eingerostet, aber eine Schleife aufzurollen ist besser als nichts, wenn Sie alles mit der CPU verschieben müssen.

    – Mikromega

    24. Juli 2011 um 2:49 Uhr


  • @R: Ich bin kein erfahrener C-Programmierer. Ich entwerfe Webanwendungen. Könnten Sie das bitte erklären? Was ist so lustig?

    – Mikromega

    28. Juli 2011 um 8:18 Uhr

  • stosd ist langsamer als mov + add (uops.info und agner.org/optimieren), auch wenn Sie den Zeiger dann nicht mit einem anderen korrigieren mussten add. Das loop Die Anweisung ist auf Intel-CPUs ziemlich langsam, wie etwa ein Durchsatz pro 5 Zyklen, was der Hauptengpass für diese Schleife ist. Außerdem verstößt dies gegen die Aufrufkonvention und zerstört die ESI und EDI des Aufrufers. Verwenden Sie EDX für einen von ihnen. Deklarieren Sie außerdem das arg als char *buffer wie ein normaler Mensch, nicht uint.

    – Peter Cordes

    17. Mai um 13:21 Uhr

1415310cookie-checkSchnelle Methode zum Kopieren des Speichers mit Übersetzung – ARGB nach BGR

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy