SSE store
-
Eigentlich wollte ich dem Compiler ja so viel arbeit wie möglich überlassen; deshalb intrinsics, da kann der Compiler z.B. die Register selbst auswählen.
Ich habe auch irgendwie das Gefühl, dass die Ausrichtung eher nach dem Zufallsprinzip stattfindet.
Und eigentlich habe ich alles probiert;
_aligned_malloc, __declspec(align ; heap oder stack. 100% hats nie funktioniert.Vielleicht klappts ja noch..aber 2 Monate wollte ich nicht daran sitzen.. :-))))
Gruß
Michael
-
hehe.. schau mal nach meinen threads
mit dem problem hab ich mich auch schon beschäftigt..
die bisher sicherste lösung war die von camper:
float *p = (float*) malloc(grösse*sizeof(float)+15), *p_aligned; p_aligned = (float*) (((unsigned)p+15)&-16); //tu was mit p_aligned free(p);
gruss
eviluser
-
Klar, ich habe Deine Threads gelesen; aber ich dachte eigentlich es geht z.B. mit _aligned_malloc.... dafür gibts das ja.
Ich werds aber auch mal so probieren...SSE muss doch irgend etwas bringen...
Gruß
Michael
-
wie gesagt, die funktion macht definitiv nicht, was sie soll - die minimumberechnung klappt schon mal nicht, weil xa ja schon durch die maximumrechnung verändert wurde. allerdings würde ich vorschlagen, zunächst dan normalen c++ quelltext zu optimieren, der ist nähmlich grauenhaft
- davon ausgehend kann man dann versuchen noch etwas mittels sse herauszuholen.
zunächst fällt auf, dass die skalierung mit .0039f völlig wertlos ist, sie fällt am ende der rechnung nähmlich wieder heraus.
auch die konstanten für cos/sin sind etwas witzlos(und im sse teil falsch):
cos(0)=1 sin(0)=0 klar
cos(2pi/3)=-1/2
cos(4pi/3)=-1/2
sin(2pi/3)=sqrt(3)/2
sin(4pi/3)=-sqrt(3)/2
damit wird
x = R*rx + G*gx + B*bx = R - 1/2 * ( G + B )
y = R*ry + G*gy + B*by = ( G - B )*sqrt(3)/2oder besser:
x = R + R - ( G + B )
y = ( G - B ) * sqrt(3)
(der faktor 2 fällt ja durch das skalieren wieder heraus)die maximum/minmumberechnung kann man auch aufschieben, bis x*x+y*y bekannt ist, im falle von 0 spart man so zeit
inline void RGB2CCdb(const unsigned char r, const unsigned char g, const unsigned char b, float &ccx, float &ccy) { ccx = (float)( r + r - g - b ); ccy = (float)( g - b ) * sqrtf( 3.0f ); float sq; if ( ( sq = ccx * ccx + ccy * ccy ) > 0 ) { float scale; if ( r >= g ) { if ( r >= b ) { if ( g >= b ) { scale = (float)( r - b ) / ( (float)r * sqrtf( sq ) ); } else { scale = (float)( r - g ) / ( (float)r * sqrtf( sq ) ); } } else { scale = (float)( b - g ) / ( (float)b * sqrtf( sq ) ); } } else { if ( g >= b ) { if ( r >= b ) { scale = (float)( g - b ) / ( (float)g * sqrtf( sq ) ); } else { scale = (float)( g - r ) / ( (float)g * sqrtf( sq ) ); } } else { scale = (float)( b - r ) / ( (float)b * sqrtf( sq ) ); } } ccx *= scale; ccy *= scale; } }
das wäre dann mal wieder ein fall wo der 2. vor dem ersten schritt der getan wurde
zu einer division durch null kann es nie kommen, denn wenn max = 0 folgt sq = 0.
-
wenn es jetzt unbedingt sse sein muss, könnte man es z.b. so machen (von vektoroperationen ist ja nichts übriggeblieben
):
inline void RGB2CCdb(const unsigned char r, const unsigned char g, const unsigned char b, float &ccx, float &ccy) { const float sqrt3 = sqrtf( 3.0f ); const float null = 0.0f; __asm { movzx eax, r cvtsi2ss xmm0, eax add eax, eax movzx ecx, g cvtsi2ss xmm1, ecx sub eax, ecx movzx edx, b cvtsi2ss xmm2, edx sub ecx, edx sub eax, edx cvtsi2ss xmm4, ecx // y mov ecx, ccx cvtsi2ss xmm3, eax // x mov edx, ccy mulss xmm4, sqrt3 movss xmm6, xmm3 movss xmm7, xmm4 mulss xmm3, xmm3 mulss xmm4, xmm4 addss xmm3, xmm4 comiss xmm3, null je get_out sqrtss xmm3, xmm3 movss xmm5, xmm0 maxss xmm0, xmm1 minss xmm5, xmm1 maxss xmm0, xmm2 minss xmm5, xmm2 mulss xmm3, xmm0 subss xmm0, xmm5 // max - min divss xmm0, xmm3 mulss xmm6, xmm0 mulss xmm7, xmm0 get_out:movss [ ecx ], xmm6 movss [ edx ], xmm7 } }
-
Hmm,
der Code ist eine Anpassung des orginal RGB2HSV Codes.(Ich glaube der orginale ist von Smith selbst). Stammt aus der Lehre und hat deshalb diese Struktur...
Ich dachte 2 Skalarprodukte und die min/max Berechnung ist schneller/sse kompatibler als die vielen if's....
Die Konstanten sind nur für die Lesbarkeit; sind ja nur Konstanten und sollten nur einmal berechnet werden. Aus diesen Werten wird eine ONB für einen Unterraum des R^3 (rgb) erzeugt; die Werte in der SSE Berechnung sind nur eine andere ONB.
Mir ist nicht ganz klar, warum die normierung der RGB Werte von [0..255] auf den Bereich [0..1] mit der multiplikation von 0.0039 rausfällt(wink mal etwas mehr mit dem Zaunfahl...
)
Schonmal
Danke danke danke....Michael
-
float scale = (delta / max) / (float)sqrt(sq); ccx = x * scale;
delta is ja max-min - max ist selbst einer der farbwerte... alle mit .0039 skaliert, (also fällt es in delta/max heraus). sqrt(sq) enthält den faktor ebenfalls, genauso wie x - also fällt es dort ebenfalls heraus.
wenn man schon floats hat ist eine max/min berechnung sicher günstiger als ifs (das hab ich im sse teil ja auch gemacht) - für integer ist das nicht so (man kann die sprünge vermeiden, wenn man movcc benutzt, aber der vergleich ist trotzdem notwendig) - in jedem falle werden integer wesentlich schneller (und zum teil parallel) verarbeitet, so dass ich ziemlich sicher bin, dass es so günstiger ist. man sollte immer bedenken, dass sse befehle an sich recht langsam sind, nur durch grossen datendurchsatz erreicht man einen geschwindigkeitsvorteil (und in manchen fällen ist man schneller als mit der fpu, die ja auch nicht schnell ist).
-
Habs jetzt auch kapiert..:-)))
Und ich muss sagen, ich bin mehr als begeistert. Vielen Dank!!
Falls Dir noch mehr gutes zu schnellem Code einfällt, auch Literatur, her damit; ich will ja nicht Dumm sterben....
Respekt.
Gruß Michael
-
da fällt mir auf:
ccx = (float)( r + r - g - b ); ccy = (float)( g - b ) * sqrtf( 3.0f );
muss nat. sein:
ccx = (float)( (int)r + (int)r - (int)g - (int)b ); ccy = (float)( (int)g - (int)b ) * sqrtf( 3.0f );
es kann ja sonst zu unangenehmen überläufen kommen (im if teil ist das ja ausgeschlossen).