Die schnellere Dialogbox

Als ST-Besitzer gibt es jede Menge Möglichkeiten mit ein paar Tricks noch ein wenig mehr aus dem Rechner herauszuholen. Hier will ich Ihnen etwas zum Thema „Dialogbox und Geschwindigkeit“ erzählen.

Grundsätzlich ist zu bedenken, daß eine Dialogbox umso schneller aufgebaut ist, je weniger zu zeichnen ist. Aus diesem Grund vermeide ich Füllmuster und unnötige Umrandungen innerhalb der Box. Da der Mensch (hierzulande zumindest) von links nach rechts und von oben nach unten liest, sollte sich eine Dialogbox genau in dieser Reihenfolge aufbauen. Der eigentliche Aufbau wird dadurch natürlich nicht schneller, dem Benutzer erscheint es jedoch so, da er sofort links oben zu lesen beginnen kann. Um diese Ordnung zu erreichen, gibt es in jedem Resource Construction Set eine Funktion zum Sortieren der Box. Da man die einzelnen Elemente aus jeder Programmiersprache mit Namen ansprechen kann, dürfte auch ein nachträgliches Sortieren keine Schwierigkeiten machen.

Daß man bei der Textausgabe unter GEM (mit v_gtext()) einen beträchtlichen Geschwindigkeitszuwachs erzielen kann, indem man beim Systemzeichensatz (bzw. bei allen 8 Bit breiten Zeichensätzen) mit der Ausgabe an Byte-Grenze beginnt, dürfte mittlerweile ein alter Hut sein. Als ich neulich mehrere Dialogboxen mit Hilfstexten in ein Programm einbaute, war ich über die unterschiedliche Zeichengeschwindigkeit der fast gleich großen Boxen doch sehr überrascht. Nach genauerer Untersuchung hatte ich des Rätsels Lösung gefunden: Die ‘schnellere’ Dialogbox hatte eine geradzahlige Zeichenbreite (Bild 1). Die AES-Funktion form_center() kann die Box dann so zentrieren, daß deren Objekte an Byte-Grenze plaziert werden. Intern werden die Strings dann mit v_gtext() auch an Byte-Grenze gezeichnet. Ist die Box aber um ein Zeichen breiter (Bild 2), werden alle Objekte an Byte-Grenze+4 gezeichnet. Dies ist natürlich langsamer.

Der Trick funktioniert natürlich nur, wenn die Objekte innerhalb der Dialogbox zeichenweise ausgerichtet sind. Bei manchen Resource Construction Sets kann man das umgehen und die Objekte beliebig positionieren. Das sollte nach Möglichkeit vermieden werden.

Der Geschwindigkeitszuwachs gilt hauptsächlich für Objekte des Typs STRING. TEXT-Objekte werden unter Umständen noch zentriert. Um hier auf Byte-Grenze zu kommen, müssen die Breite des Objekts und die String-Länge geradzahlig sein (oder beides ungeradzahlig). Beim Konstruieren einer Box sollten die Buchstaben in x-Richtung immer gleich ausgerichtet sein.

Neuerdings kommt es immer mehr in Mode, sich eigene Objekte (z.B. Mac-Buttons) zu definieren (ja, hab’ ich auch schon gemacht...). Auch hierbei sollte man das oben Gesagte berücksichtigen. Bei meinen Mac-Buttons wird zuerst der Knopf gezeichnet und dann rechts daneben der Text. Um die x-Koordinate für v_gtext() zu bestimmen, sollte man zur x-Koordinate, die man vom GEM erhalten hat, ein Vielfaches von 8 addieren. Wurde die Box auf Byte-Grenze zentriert, werden auch die neuen Objekte mit Maximalgeschwindigkeit gezeichnet.

Wenn wir schon bei den benutzerdefinierten Objekten sind: In letzter Zeit mußte ich überall lesen, daß man mit dem LASER C-Compiler keine benutzerdefinierten Objekte erstellen könne. Vielleicht mache ich ja etwas falsch, aber bei mir funktioniert das einwandfrei. Lokale Variablen werden auf dem Stack abgelegt und sind so ganz normal zugänglich. Globale Variable werden direkt adressiert und nicht wie früher beim MEGAMAX C indirekt über ein Adreßregister. Deren Verwendung ist also kein Problem mehr.

Bei der Dialogbox Verwaltung kann man einiges an Zeit gewinnen, wenn man die AES-Funktionen form_dial() nicht benutzt und den Hintergrund selbst (und zwar richtig) rettet. Dazu muß man aus der Größe des zu sichernden Bereichs und der Anzahl der Bitplanes den Speicherbedarf berechnen, Speicher anfordern und den Bildschirmbereich mit Hilfe von vro_cpyfm() dort hinkopieren. „Ja, ja, weiß ich doch schon alles“, werden Sie nun zu recht sagen. Aber wissen Sie auch, wie man die vro_cpyfm()-Funktion so richtig ausnutzt?

Also mal angenommen, wir haben an den Koordinaten [555,473] (Großbildschirm) ein Rechteck mit der Ausdehnung [217,59]. Die Werte spielen dabei absolut keine Rolle. Das ist also unser Quellrechteck. Kopiert wird es nun nach [0,0] in unseren Speicher (natürlich wieder mit der Ausdehnung [217,59]. Was ist daran falsch? Um ehrlich zu sein: nichts, aber ... es geht schneller. Betrachten wir nun nur die x-Koordinaten. Jede Linie wird von der Position 555 auf 0 gebracht. Da 555 nicht im geringsten durch 16 teilbar ist, 0 aber sehr wohl, muß der komplette Block Wort für Wort geshiftet werden. Das kostet extrem viel Zeit (analog der Text-Shifterei oben). Und da beim Restaurieren der ganze Block wieder zurückgeshiftet werden muß, haben wir gleich zweimal sinnlos Zeit verbraten.

Da 555 mod 16 = 11 ist, verschieben wir das Rechteck besser nach [11,0]. Die Shifterei entfällt, und das Kopieren wird sichtbar schneller. Man muß natürlich noch berücksichtigen, daß man 1 Wort pro Zeile mehr Speicher braucht, aber das fällt kaum ins Gewicht.

Kommen wir nun zum Listing. Das Programm ist bewußt einfach gehalten, man bekommt als Ergebnis nur die Meßwerte geliefert. Von der Kopiererei sieht man nichts. Sie dürfen also nich enttäuscht sein...

In der Funktion main() melden wir uns beim VDI an. In test() holen wir uns die Koordinaten des Desktop-Hintergrunds (Window 0). Diesen Bereich wollen wir verschieben. Dann werden die beiden MFDBs ausgefüllt und Speicher zum Verschieben angefordert.

Wenn wir diesen erhalten, werden die Maus ausgeschaltet (stört nur) und die aktuellen Daten des Bildschirms ausgegeben (der Betrachter will ja auch was sehen). Dann werden 2 Tests durchgeführt (und zwar jeweils 16mal für alle möglichen Offsets zur Wort grenze): Test 1 verschiebt immer zur Wortgrenze. Bei Test 2 dagegen verschieben wir an die x-Koordinate mod 16. Die Funktion doJestO führt die Messung durch und gibt die Zeiten aus. Das Rechteck wird jeweils 10mal vom Bildschirm in den Speicher kopiert. Da man beim Zurückkopieren sowieso nichts sehen würde, weil sich der Bildschirm in der Zwischenzeit nicht verändert hat, wird dies unterlassen. copy() übersetzt die Parameter in eine dem VDI verständliche Form und ruft dieses dann auf. get_timer() liest den 200 Hz-Systemtakt aus.

# vro_cpyfm()-Geschwindigkeitsdemo
   
Auflösung: 639x399
Farbebenen: 1
Rechteck: [0,19][623,399]
Speicher: 30480
Test 1: Test 2:
von nach Zeit (ms) von nach
0 0 830 0 0
1 0 1675 1 1
2 0 1680 2 2
3 0 1755 3 3
4 0 1760 4 4
5 0 1830 5 5
6 0 1830 6 6
7 0 1905 7 7
8 0 1905 8 8
9 0 1900 9 9
10 0 1830 10 10
11 0 1830 11 11
12 0 1755 12 12
13 0 1750 13 13
14 0 1675 14 14
15 0 1675 15 15

gemessen auf ATARI ST 8 MHz, TOS 1.4, kein Blitter, Auflösung 640x400

Bild 1: 30 Zeichen breite Box
Bild 2: 31 Zeichen breite Box
/********************************************/
/*                                          */
/*    vro_cpfm.c                            */
/*    vro_cpyfm() Speed Demo                */
/*                                          */
/*    Programmiert mit LASER C V2.1 von     */
/*                                          */
/*    Ulrich Mast                           */
/*                                          */
/*    (c) 1991 MAXON Computer               */
/*                                          */
/********************************************/
#include    <osbind.h>
#include    <gemdefs.h>

#define     HZ_200      0x4BA

int     contrl[12],
    intin[128],intout[128], 
    ptsin[128],ptsout[128];

int     vdi_handle,
    vdi_planes, 
    vdi_w, 
    vdi_h; 
int     work_out[57],
    work_in[]={1,1,1,1,1,1,1,1,1,1,2};
MFDB screen,mem;


long
get_timer()
{
    long    stack; 
    long    timer;

    stack=Super(0L); 
    timer=*(long*)HZ_200;
    Super(stack); 
    return(timer);
}

copy(x,y,w,h,diff) 
int     x,y,w,h,diff;
{
    int     xy[8];

    xy[0]=x;        /* Quelle */
    xy[1]=y; 
    xy[2]=x+w-1;
    xy[3]=y+h-1;
    xy[4]=diff;     /* Ziel */
    xy[5]=0;
    xy[6]=w-1+diff;
    xy[7]=h-1;

    vro_cpyfm(vdi_handle,3,xy,&screen,&mem);
}

do_test(x,y,w,h,diff) 
int     x,y,w,h,diff;
{
    long    timer; 
    int     i;

    timer=get_timer(); 
    for(i=0;i<10;i++)
        copy(x,y,w,h,diff); 
    printf(”%3d %4d %1d\n",x,diff,(get_timer()-timer)*5L);
}

test()
{
    int     x,y,w,h;
    long    len; 
    int     i;

    wind_get(0,WF_WORKXYWH,&x,&y,&w,&h); 
    w-=16;

    screen.fd_addr=0L;

    mem.fd_nplanes=vdi_planes; 
    mem.fd_wdwidth=(w+31)/16; 
    mem.fd_w=mem.fd_wdwidth*16; 
    mem.fd_h=h; 
    mem.fd_stand=0;

    len=2L;
    len*=(long)mem.fd_wdwidth; 
    len*=(long)mem.fd_h; 
    len*=(long)mem.fd_nplanes;

    mem.fd_addr=Malloc(len); 
    if(!mem.fdaddr)
    {
        form_alert(1,"[3][ Nicht genug Speicher ! ][Oha]");
        return;
    }

    graf_mouse(M_OFF,0L);

    printf("\nvro_cpyfm() Speed Demo\n\n"); 
    printf("Auflösung:  %d x %d\n",vdi_w,vdi_h);
    printf("Farbebenen: %d\n",vdi_planes);
    printf("Rechteck:   [%d,%d] [%d,%d]\n",x,y,x+w-1,y+h-1); 
    printf("Speicher:   %1d\n\n",len);

    printf("Test 1:\n\n");
    printf("von nach Zeit (ms)\n");
    for(i=0;i<16;i++)
        do_test(x+i,y,w,h,0); 
    printf("Taste...\n\n");
    Cconin();

    printf("Test 2:\n\n");
    printf("von nach Zeit (ms)\n");
    for(i=0;i<16;i++)
        do_test(x+i,y,w,h,(x+i)%16);

    printf("Taste...\n\n");
    Cconin () ;

    graf_mouse(MON,0L);

    Mfree{mem.fd_addr);
}

main(argc,argv) 
int argc;
char *argv[];
{
    int     d;

    appl_init(); 
    graf_mouse(ARROW,0L);

    vdi_handle=graf_handle(&d,&d,&d,&d); 
    v_opnvwk(work_in,&vdi_handle,work_out); 
    if(vdi_handle)
    {
        vdi_w=work_out[0]; 
        vdi_h=work_out[1];

        vq_extnd(vdi_handle,1,work_out); 
        vdi_planes=work_out[4];

        test();

        v_clsvwk(vdi_handle);
    }
    else
        form_alert(3,"[1][ Kann vWK nich Öffnen ! ][Hmnm]");

    appl_exit();
}

Ulrich Mast
Aus: ST-Computer 07 / 1991, Seite 88

Links

Copyright-Bestimmungen: siehe Über diese Seite