Seite 1 von 1

Merkwürdiges Verhalten bei setPixel Operationen unter MSVC

Verfasst: 19.01.2012, 21:24
von Hellhound
Hallo zusammen,

seit einiger Zeit bin ich damit beschäftigt unseren Code auf den MSVC lauffähig zu machen. Soweit so gut, nun habe ich bei einzelnen get/setPixel
Operationen ein merkwürdiges Problem bei nicht nativen Formaten (SHORT RGB(A) und FLOAT16). Führe ich meine UnitTests oder Demos aus, dann
wird die Applikation beim Setzen der Werte unter dem MSVC extrem stark verlangsamt (mehrere Sekunden) unter dem GCC läuft alles völlig normal,
in einem Bruchteil von Sekunden ab.

Da das ganze etwas schwierig zu erklären ist, hier ersteinmal die Code Fragemnte:

Code: Alles auswählen

void brImage::setPixelColor(const brRectangle<unsigned int>& rect, const brColor& color)
{
brPixelFormatInfo info = gfxUtils.getPixelFormatInfo(m_format);
unsigned int nativeColor = 0;
// if pixel format is native first calculate the native color before
// entering loop to set color value.
if(true==info.isNativeEndian()){
        nativeColor = this->getNativePixelColor(color);
}
unsigned int bytesPerPixel = this->getBytesPerPixel();
for(unsigned int y = rect.getY(); y < rect.getY()+ rect.getHeight(); y++)
{
          // calculation of the image value stride
          unsigned int byteIndex = (this->getBytesPerRow() * y) + rect.getX() * bytesPerPixel;
                for (unsigned int x = rect.getX(); x < rect.getX()+rect.getWidth(); x++)
                {
                        if(true==info.isNativeEndian())
                        {  
                                [...]
                        }
                        else{
                                switch(m_format)
                                {
                                        // 32bit float value formats
                                        case PF_FLOAT32_RGB:
                                        {
                                                m_data[byteIndex]        = (unsigned char)color.getRed();
                                                m_data[byteIndex + 1] = (unsigned char)color.getGreen();
                                                m_data[byteIndex + 2] = (unsigned char)color.getBlue();
                                                break;
                                        }
                                        case PF_SHORT_RGB:
                                        {
                                          unsigned int red, green, blue = 0;
                                          brPixelFormatInfo info = gfxUtils.getPixelFormatInfo(PF_SHORT_RGB);
                                          brPixelFormatInfo::RGBA_BITS bits = info.getBitValues();
                                          brColor::RGBA rgba = color.getRGBA();
                                          red   = gfxUtils.convertColorToFixedPoint(rgba.m_red, bits.m_red);
                                          green  = gfxUtils.convertColorToFixedPoint(rgba.m_green, bits.m_green);
                                          blue   = gfxUtils.convertColorToFixedPoint(rgba.m_blue, bits.m_blue);
        
                                          m_data[byteIndex]      = (unsigned char)red;
                                          m_data[byteIndex + 1] = (unsigned char)green;
                                          m_data[byteIndex + 2] = (unsigned char)blue;
                                break;
                                        }
                                        // half float precision values
                                        case PF_FLOAT16_R:
                                        {
                                                brColor::RGBA rgba = color.getRGBA();
                                                m_data[byteIndex] = (unsigned char)gfxUtils.convertColorToHalfFloat(rgba.m_red);
                                                break;
                                        }
                                        default:
                                                throw brCore::brIllegalStateException(
                                                "[brImage]::setPixelColor: Invalid pixel format!");
                                }
                        }
                        byteIndex += bytesPerPixel;
                }
   }
}

Code: Alles auswählen

unsigned int brGraphicsUtils::convertColorToFixedPoint(float color, unsigned int bits) const
{
   unsigned int fixed = 0;
        if(color <= 0.0f){
                fixed = 0;
        }
        else if (color >= 1.0f){
                fixed =  (1U<<bits)-1U;
        }
        else{
                fixed = (unsigned int)(color * (1U<<bits));
        }
        return fixed;
}
Wenn man den Code anschaut eigentlich nichts weltbewegendes. Was mich vorallem stutzig macht, ist dass wenn ich mit dem MSVC debugge und
in Einzelschritten über die Aufrufe husche, wirkt alles "normal" schnell, die Aufrufe kommen schnell zurück. Rufe ich in meinem Test jedoch die
setPixelColor Methode als Prozedurschritt auf, dann dauert es etwa 1-3Sek. bevor der Aufruf aus der Methode zurückkehrt ...

Zur Evaluierung habe ich mal an der SHORT_RGB Auswertung Messpunkte eingebaut die mir die Systemzeit vor und nach den Operationen bzw.
beim betreten und Verlassen der Methode liefern:
- in: 2012-Jan-19 15:44:52.664127
- start convert: 2012-Jan-19 15:44:52.669127
- end convert: 2012-Jan-19 15:44:52.690127
- start writing: 2012-Jan-19 15:44:52.695127
- end writing: 2012-Jan-19 15:44:52.700127
- out: 2012-Jan-19 15:44:52.705127
Es sieth so aus, als ob die Konvertierung nicht der Kasus Knaxus ist, sondern das das Schreiben der Daten einiges an Zeit schluckt. Aber
das bei den simplen Aufrufen? Ich kann mir das ganze nicht mehr erklären und warum nur auf dem MSVC? Unter dem GCC läuft der Code
sowohl für Linux als auch Windows flott durch ... Es betrifft auch nur die SHORT_RGB, SHORT_RGBA und FLOAT_16 Formate, die FLOAT32
Formate gehen problemlos durch ...

Hat jemand evtl. eine Idee was hier schief laufen könnte? Mir gehen allmählich die Ideen aus ...

Gruß
Hellhound

P.s: Den gesamten Code kann man hier einsehen:
http://binrevengine.svn.sourceforge.net ... hound-dev/

Re: Merkwürdiges Verhalten bei setPixel Operationen unter MS

Verfasst: 20.01.2012, 08:47
von Schrompf
Visual Studio - Debug oder Release Build? Nur letzterer ist schnell. Außerdem enthält Dein Code ein paar Ecken, die potentiell sehr langsam sein können. Ich weiß nicht, wie komplex die brPixelFormatInfo ist, aber die z.B. kopierst Du mehrfach lokal, obwohl eine const reference reichen würde. Wenn diese Klasse ein paar Strings oder sowas enthält, wäre das schon eine mögliche Erklärung. Vielleicht erkennt der GCC, dass Du das Objekt nur lesend benutzt, während Visual C++ keine solche Optimierung benutzt.

Re: Merkwürdiges Verhalten bei setPixel Operationen unter MS

Verfasst: 20.01.2012, 09:06
von Hellhound
Aktuell teste ich im Debug mode. Hmm, mit der Optimierung hast Du recht, das sollte ich mal anpassen, hab auch schon daran gedacht in den eigentlichen
Konvertierungsmethoden die If-Bedingungen heraus zu nehmen, da die ja pro Pixel geprüft werden und durch Asserts zu ersetzen. Pixel Info ist soweit ich
das sehe aber nicht die Problemstelle, denn für alle anderen Formate ist der Zugriff auf setPixelColor schnell und die nutzen diese ja auch ...

Re: Merkwürdiges Verhalten bei setPixel Operationen unter MS

Verfasst: 20.01.2012, 10:44
von Hellhound
Ich habe mir mal die Trial Version des VTunes Amplifier gezogen und das ganze mal getestet.
Schrompf Du hattest die richtige Vermutung, es sind vermutlich meine Debug Logs, die hier
enorm runter bremsen. Der GCC scheint hier was String Zugriffe angeht zu optimieren ...

http://j18.img-up.net/?up=Profile9r2h1.jpg

Der Amplifier ist ja nen nettes Tool, aber 800$ für ne Single User Lizenz ganz schön happig.
Hab mal von AMD den CodeAnalyzer aus- probiert, der liefert mir aber (Intel Proz.) nicht so
tolle Infos ... Zumindest nicht so super übersichtlich ...

Danke für den Hinweis Shrompf!