Put-Pixel-Routine beschleunigen
-
Sicher. Nur ist dabei nicht sichergestellt, dass Register geshifted werden und nicht gleich die Variablen im Speicher/Stack. Das dauert bis zu 3clocks laenger. Falls ich mich in diesem Punkt irren sollte bitte ich um Aufklaerung
-
Genau in diese Richtung zielte meine Frage, vielen Dank Nubuo T.
Könntest du mir den genauen nötigen Code dafür schreiben, wie müsste das in der C-Fkt aussehen ?
-
hm. also die c++-Variante lass ich besser erstmal sein. Dabei ist mir als c++-laie noch einiges unklar. zB. welches Betriebssystem wird benutzt? Real oder Protected mode? Welche Form hat dieser *adr-pointer genau, etc. Also beschraenke ich mich hier mal auf die reine Real mode Assembler version.
;bl=color
mov di,[x]
mov ax,[y]
shl ax,06h ;(*64)
add di,ax
shl ax,02h ;(*64*4=*256)
add di,ax
mov ax,0A000h ;segment der VGA
mov ds,ax
mov [ds:di],bl
das sind insgesamt (auf 486+CPU) 13 clocks...
So viel, wie sonst allein die Multiplikation verbraucht haette...
-
Original erstellt von Nobuo T:
**
13 clocks fuer eine unsigned 16Bit-Multiplikation mit Registern.
**ich hab hier n buch wo für so eine multiplikation 11 clocks drinn steht... und das auf pentium bezogen... ich nehmen an ein athlon oder P3/P4 dürfte da noch massiv schneller sein
-
Mag sein. Fakt ist aber, dass shift dann immernoch schneller sein wird
Diese Werte (fuer 486CPU) sollen eigentlich nur zum Vergleich dienen.
-
@Nobuo T
Wenn man weis wie der compiler optimiert kann man mit "const" angaben die variablen in register "lenken". Und ohnehin sollte der compiler alles was reinpasst in registern aufbewahren.@Steffen Vogel:
So kleine funktionen durch asm zu optimieren halte ich für falsch. Wenn das prog. schneller laufen soll, dann solltest Du Dein konzept ändern.
-
Was bitte ist an Optimierungen - egal welcher Art - falsch?? Gerade eine so elementare Funktion wie die putPixel sollte möglichst schnell sein, besonders dann, wenn sie oft verwendet wird.
Klar, ist ein gutes Konzept wichtiger, aber gerade da soviele auf Feintuning verzichten, sind die Spiele von heute viel langsamer als sie sein müßten.Übrigens gabs hier schonmal eine vergleichbare Diskussion um putPixel.
-
Original erstellt von <Steffen Vogel>:
Könntest du mir den genauen nötigen Code dafür schreiben, wie müsste das in der C-Fkt aussehen ?void fast_put_pixel(int x, int y, int color, unsigned char *adr) { *(adr+x+((y<<8)+(y<<6)))=color; }
so würde das in C aussehen.
Aber dazu noch was interessantes, dass macht der gcc 3.0.4 aus dem put_pixelput_pixel: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax leal (%eax,%eax,4), %eax sall $6, %eax addl 20(%ebp), %eax movl 16(%ebp), %ecx movl 8(%ebp), %edx movb %cl, (%edx,%eax) popl %ebp ret
und das aus fast_put_pixel (!)
fast_put_pixel: pushl %ebp movl %esp, %ebp movl 12(%ebp), %edx movl %edx, %eax movl 20(%ebp), %ecx sall $6, %eax sall $8, %edx addl 8(%ebp), %ecx addl %eax, %edx movl 16(%ebp), %eax movb %al, (%edx,%ecx) popl %ebp ret
(noch mein Senf zur Welt:
In der Regel optimieren Compiler schon verdammt gut, nur bei wirklich harten Dingen sollte man Assembler einsetzen, aber da fällt mir spontan nichts ein ;))
-
hi,
wie ruft man die funktion:
void fast_put_pixel(int x, int y, int color, unsigned char *adr)
{
*(adr+x+((y<<8)+(y<<6)))=color;
}
dann auf?
die ersten drei parameter sind klar, aber was soll ich da für nen pointer übergeben?
-
Hi!
Ich bin zwar schon ne ganze Weile weg vom Assembler, aber damals habe ich das etwas anders gemacht. Ich habe nämlich ein Zeilen-Array reserviert, in dem die Start-Adresse jeder Grafikzeile stand.
Also war z.B.:grRowArr[0] == 0
grRowArr[1] == 320
grRowArr[0] == 640usw. Das geht dann ein bissl schneller als Multiplikation und auch als Shifts. Wollt ich nur mal so ansprechen, weil diese Möglichkeit hier noch niemand erwähnt hat
... und der Gra-Speed hat da rult
@BlockBuster: adr dürfte hier 0xA000h bzw Start des GrafikScreens sein.
-
Wohl kaum schneller als Shifts. Ein shl eines 16-Bit-Registers brauchte schon auf dem 8086 nur 2 Takte, wobei ein add eines 16-Bit-Registers mit einer Speicherstelle darauf mehr als 9 Takte brauchte. Auf nem Pentium war das also höchstens gleich schnell (je 1 Takt
), wobei allerdings nach deiner Methode 200 Bytes fürs Array verbraten werden.
[ Dieser Beitrag wurde am 06.06.2002 um 18:47 Uhr von Cocaine editiert. ]
-
Bleiben wir doch mal realistisch: 8086
Fangen wir mal mit 486er an. Ich poste mal eben PseudoCode und zwar für PM. RM kann ja umsetzen wer will:; ============================= @Putpixel: ; ============================= ; IN: EAX= X-Position ; ECX= Y-Position ; BL = Color add eax, [ecx*2+arrOfRows]; Oder vorher shl ecx, 2 ... ich kenn jetzt die clocks net add eax, [videoAdress] ; On Screen mov [eax], bl ; set color ret
Hier gehe ich natürlich von einem FlatSegment und CS=DS aus. Ich spare hier übrigens nicht nur ein Shift sondern 2. Und zusätzlich noch Additionen. Ausserdem sche|ss ich erlich gesagt prinzipiell auf extra reservierten Speicher wenn man Speed dafür rausholen kann
.
Falls es trotzdem Blödsinn ist, dann sorry und belehr mich - bin schon zu lang raus
. Aber ich errinnere mich gut, daß ich das Tage lang abgewogen und mich dann dafür entschieden habe
.
-
@Nubuo T: Hast du eine Liste der Taktzyklen der einzelnen Befehle ?
-
@blockbuster: Die Funktion stellt einen Punkt an der Stelle eines Speichers dar, dessen Adresse du ihr mit adr übergibst. Somit kannst du entweder direkt in den Videospeicher schreiben oder in einen Puffer, den man dann später ins Videoram kopiert. Sowas macht zum Beispiel Sinn, wenn man mehrere Punkte zeichnen lassen will, aber das Bild auf einmal erscheinen soll und nicht punktweise.
Ich hoffe, du verstehst jetzt wie du diese Fkt benutzt.
-
Ich habe eine Befehlsreferenz, bei der uA. auch die benoetigte Anzahl von Tacktzyklen pro Befehl drinstehen. Leider ist das ein Buch, also wirds schwer mit dem Posten o.ae.
Kauf dir den TASM von Borland. Da ist diese Befehlsreferenz und noch ein Haufen anderes Zeug mit bei
-
@Steffen Vogel achso... naja und welche adresse muss ich jetzt übergeben wenn ich was direkt auf den bildschirm malen will?
-
Dafür musst du die Adresse des Bildschirmspeichers nehmen.
Ich mache das immer so:unsigned char _far *vidmem = (unsigned char _far *)0xA0000000;
Und dann rufe ich put_pixel(10,10,5,vidmem);
auf, damit ein Punkt bei 10,10 mit der Farbe 5 gemalt wird.
Also Puffer würde man halt vorher definieren:
unsigned char puffer[64000];
und dann entsprechend
put_pixel(10,10,5,puffer);
aufrufen.
Um das Bild in den Bildschirmspeicher zu kopieren mache ich:
movedata(FP_SEG(puffer),FP_OFF(puffer),FP_SEG(vidmem),FP_OFF(vidmem),64000);Ich hoffe ich konnte deine Frage klären und wünsche dir viel Spaß beim Ein- und Umsetzen der neuen Kenntnisse.
-
@Steffen Vogel hey, danke!
jetzt weiß ich alles was ich wissen will, bis auf eins
die funktion movedata kann ich ja net aufrufen wenn ich unter keinem OS arbeite... wie kann ich das dann machen?
-
LOL, erzähl jetzt bitte nicht - Du willst ein OS proggen und weisst nicht mal wie man Daten kopiert
-
@VollTroll-Germania doch schon... aber ich weiß net genau was die movedata funktion macht