Code Optimierung

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Code Optimierung

Beitrag von snapdragon »

Ich habe vorhin ein swapping für DX Textur eingebaut um meine RGBA Bilddaten in BGRA Daten
zu swappen:

Code: Alles auswählen

      const unsigned char* src = m_image->getImageData();
      unsigned int width = image->getWidth();
      unsigned int height = image->getHeight();
      unsigned int len = width*height*4;

      unsigned char* dst = new unsigned char[len];
      for(int i=0; i<len; i+=4){
          dst[i] = src[i+2];         //B
          dst[i+1] = src[i+1];       //G
          dst[i+2] = src[i];         //R
          dst[i+3] = src[i+3];       //A
     }

     unsigned int stride = m_image->getBytesPerRow();

     for(unsigned int y=0; y<m_image->getHeight(); ++y){
          unsigned char* dxData = (unsigned char*)m_locked.rect->pBits + y * m_locked.rect->Pitch; 
	  memcpy(dxData, dst + y*stride, stride);  
     }
Klappt mit diesem Snipped auch wie gewünscht. Nur gefällt mir der Algorithmus nicht, da ich hier zwei Schleifen durchlaufen muss.
Seht Ihr eine Möglichkeit? Irgendwie bekomme ich das grad nicht gebacken und erzeuge nur Buffer overflows :evil:
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

Warum musst du überhaupt swappen und wenn du swappen musst, wieso kannst du das nicht einfach direkt beim Befüllen der Textur machen?
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Die Bilddaten werden separat geladen und liegen im vertauschten Farbformat vor, deshalb das swapping.
Und mit diesen Daten befülle ich ja meine Textur (dxData ist ja der Zeiger auf den Texturbuffer) ...
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

Naja, aber dann kannst du die Daten aber doch einfach direkt beim reinschreiben in die Textur swappen, anstatt erstmal alles in einen temporären Buffer zu stecken!?
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Wenn wir beide unter direkt verstehen, das dst = m_locked.rect->pBits ist, dann habe ich das bereits ausprobiert.

Hier sind dann zwar die Kanäle korrekt ausgetauscht, aber ich habe dann Texturfehler. Meine Vermutung liegt
darin, dass der Texturbuffer etwas größer ist als mein Imagebuffer.
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

Ist m_locked.rect->pBits nicht ein Zeiger auf den Speicherbereit, in den du die Daten reinkopieren willst?
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Wenn ich das richtig verstanden habe ja.
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

Ok, nun, deiner Beschreibung nach würde ich mal vermuten, dass du bei diesem Versuch des direkt reinschreibens den Pitch deines D3DLOCKED_RECT ignoriert hast!?
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Irgendwie kann ich Dir grad nicht folgen.
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

Na zeig mal wie dein direkter Versuch ohne temporären Buffer ausgesehen hat.
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Code Optimierung

Beitrag von eXile »

snapdragon hat geschrieben:Die Bilddaten werden separat geladen und liegen im vertauschten Farbformat vor, deshalb das swapping.
Und mit diesen Daten befülle ich ja meine Textur (dxData ist ja der Zeiger auf den Texturbuffer) ...
Es wird nicht ganz ersichtlich, ob du die Textur jeden Frame befüllen musst, oder nur einmal am Anfang.

Wenn du die Textur jeden Frame befüllen musst, würde ich dringend empfehlen die Textur mitsamt Pitch in RGBA im Speicher vorzuhalten, dann zu Mapen, ein einziges memcpy und dann Unmapen. Hintergrund ist, dass die Zeit zwischen Map und Unmap um jeden Preis minimal gehalten werden sollte, was in der Praxis auf ein einziges memcpy hinausläuft.

Sollte die Textur nur einmal am Anfang geladen werden, so würde ich die Textur (ohne temporäre Buffer, etc.) einfach direkt in einer Schleife befüllen (und dabei natürlich auf den Pitch achten).
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Sollte die Textur nur einmal am Anfang geladen werden, so würde ich die Textur (ohne temporäre Buffer, etc.) einfach direkt in einer Schleife befüllen (und dabei natürlich auf den Pitch achten).
Yepp, die Textur wird nur am Anfang einmal geladen und das swapping durchgeführt. Ich hatte es "direkt" versucht, indem ich hier ein swizzling der Farbwerte durchgeführt habe:

Code: Alles auswählen

 unsigned int bpp = image->getBytesPerPixel();
 int rows = image->getHeight();
 int cols = image->getWidth();

 unsigned char* dst = (unsigned char*)m_locked.rect->pBits;
 unsigned char* src = (unsigned char*)image->getImageData();

 for(int y=0; y<rows; y++)
 {
	for(int x=0; x<cols; x++)
	{
              	int   c = (y*rows + x)*bpp;

                unsigned int r = (src[c]<<16); 
                unsigned int g = (src[c+1]<<8); 
                unsigned int b = (src[c+2]<<0); 
                unsigned int a = (src[c+3]<<24); 

                dst[c] = D3DCOLOR_ARGB(a, r, g, b);
                dst += m_locked.rect->Pitch / sizeof(unsigned char);
        }
}
Das war aber zu langsam und führte zu Texturfehlern. Daher der andere Ansatz, der bei weitem schneller ist als das swizzling. Hatte ich hier etwas falsch gemacht?
Zuletzt geändert von snapdragon am 28.11.2012, 10:49, insgesamt 1-mal geändert.
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

snapdragon hat geschrieben:Hatte ich hier etwas falsch gemacht?
Ja, der Pitch ist der Abstand von einer Zeile zur nächsten nicht von einem Pixel zum nächsten. Was genau ist j? Wofür genau ist es überhaupt da drin? Und das mit der Extraktion der Farbkomponenten solltest du dir nochmal sehr genau überlegen...
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Sorry, j ist c gewesen, war ein Tippfehler. Hab ich korrigiert.

Um die Extraktion der Farbkomponenten zu vermeiden, hab ich es ja umgestellt, dann lande ich aber wieder bei meinem temporären buffer. Irgendwie bin ich hier gedanklich grad komplett blockiert :?
antisteo
Establishment
Beiträge: 941
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: Code Optimierung

Beitrag von antisteo »

Für derartige Anwendungen wurde doch eigentlich MMX erfunden...
http://fedoraproject.org/ <-- freies Betriebssystem
http://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Code Optimierung

Beitrag von dot »

Klar, natürlich könnte man das mit MMX bzw. heutzutage wohl SSE oder gar AVX noch zusätzlich optimieren...
Benutzeravatar
Schrompf
Moderator
Beiträge: 5161
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Code Optimierung

Beitrag von Schrompf »

Woher stammt denn die ImageData? Kannst Du nicht einfach direkt darin die Bytes vertauschen?

Code: Alles auswählen

len /= 4;
for( size_t a = 0; a < len; ++a )
{
  std::swap( src[0], src[2]);
  src += 4;
}
Das vermeidet den Umweg über einen temporären Buffer. Und da man eine Textur eh von Platte lädt, in den VideoRAM hochlädt und danach wegwirft, müsstest Du ImageData doch verändern können, wie es Dir beliebt.

Weitergehende Optimierungen, falls es Dir nicht schnell genug ist, wären dann MMX/SSE und Konsorten (mit denen ich mich aber nicht auskenne) oder z.B. die Behandlung von mehreren Bytes auf einmal. Man könnte das ja (vorausgesetzt die Anzahl Pixel ist immer durch zwei teilbar) auch gleich in einem uint64_t abhandeln:

Code: Alles auswählen

len /= 8;
uint64_t* data = reinterpret_cast<uint64_t*> (bla);
for( size_t a = 0; a < len; ++a )
{
  uint64_t w = *data;
  // Achtung: Endianess!
  w = (w & 0xff00ff00ff00ff00ull) | ((w << 16) & 0x00ff000000ff0000ull) | ((w >> 16) & 0x000000ff000000ffull);
  *data++ = w;
}
Das könnte evtl. ein bisschen was sparen, weil Du nicht mehr einzelne Bytes umherschiebst, sondern die ganze Operation als lineare Mathematik komplett in Registern abläuft. Bei den langen Pipelines heutiger CPUs könnte es sich auch lohnen, die Operation gleich viermal oder so hintereinander in die Schleife zu schreiben, damit die CPU die Latenzen beim Warten auf Zwischenergebnisse besser verstecken kann. Und wenn das dann immer noch nicht reicht, könnte ein schlichtes "#pragma omp parallel for" nochmal Faktor vier oder so rausholen.
}
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
snapdragon
Beiträge: 28
Registriert: 24.09.2012, 14:49

Re: Code Optimierung

Beitrag von snapdragon »

Hey danke Schrompf für den Tipp. Manchmal sieht man den Wald vor lauter Bäumen nicht ;)
Denke das direkte manipulieren des Imagebuffers sollte völlig ausreichend sein. Vielleicht
schaue ich mir in einer ruhigen Minute einmal die 64bit Optimierung an ...
Antworten