Seite 1 von 1

Code Optimierung

Verfasst: 27.11.2012, 21:49
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:

Re: Code Optimierung

Verfasst: 27.11.2012, 21:56
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?

Re: Code Optimierung

Verfasst: 27.11.2012, 22:11
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) ...

Re: Code Optimierung

Verfasst: 27.11.2012, 22:18
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!?

Re: Code Optimierung

Verfasst: 27.11.2012, 22:39
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.

Re: Code Optimierung

Verfasst: 27.11.2012, 22:49
von dot
Ist m_locked.rect->pBits nicht ein Zeiger auf den Speicherbereit, in den du die Daten reinkopieren willst?

Re: Code Optimierung

Verfasst: 27.11.2012, 22:54
von snapdragon
Wenn ich das richtig verstanden habe ja.

Re: Code Optimierung

Verfasst: 27.11.2012, 22:59
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!?

Re: Code Optimierung

Verfasst: 27.11.2012, 23:12
von snapdragon
Irgendwie kann ich Dir grad nicht folgen.

Re: Code Optimierung

Verfasst: 27.11.2012, 23:18
von dot
Na zeig mal wie dein direkter Versuch ohne temporären Buffer ausgesehen hat.

Re: Code Optimierung

Verfasst: 28.11.2012, 00:13
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).

Re: Code Optimierung

Verfasst: 28.11.2012, 09:37
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?

Re: Code Optimierung

Verfasst: 28.11.2012, 10:05
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...

Re: Code Optimierung

Verfasst: 28.11.2012, 10:49
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 :?

Re: Code Optimierung

Verfasst: 28.11.2012, 14:23
von antisteo
Für derartige Anwendungen wurde doch eigentlich MMX erfunden...

Re: Code Optimierung

Verfasst: 28.11.2012, 14:27
von dot
Klar, natürlich könnte man das mit MMX bzw. heutzutage wohl SSE oder gar AVX noch zusätzlich optimieren...

Re: Code Optimierung

Verfasst: 28.11.2012, 15:07
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.
}

Re: Code Optimierung

Verfasst: 28.11.2012, 15:42
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 ...