Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

kiba

Alter Hase

  • »kiba« ist der Autor dieses Themas

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

1

24.06.2010, 15:14

Performence in blit/blt

hi, ich würde gern wissen ob ich meine funktion optimieren könnte aber ich hab ka wie ich das machen soll.
Hat vll jemand ideen was ich verbessern könnte.
Das Problem ist ja ich muss gleichzeitig beim kopieren das Alphablending berechnen.
Wenn es RGB(ohne Alpha Kan.) ist dann könnte ich es ja einfach per memcpy kopieren.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
void Bitmap::blt_image(const ubyte* src_data,
                            int src_xstart, int src_ystart, uint src_width,
                            uint src_bytepp,
                            uint src_bitmapwidth,uint src_bitmapheight,

                            ubyte* dst_data,
                            int dst_xstart, int dst_ystart,uint dst_width,
                            uint dst_bytepp,
                            uint dst_bitmapwidth,uint dst_bitmapheight,

                            uint width, uint height,
                            bool blend, uint8 alpha)
{
    if(blend && alpha < 1)
        return;
    if(!src_data || !dst_data)
        return;

    //outside of Bitmap
    if(src_xstart > static_cast<int>(src_bitmapwidth) || src_ystart > static_cast<int>(src_bitmapheight))
        return;
    if(dst_xstart > static_cast<int>(dst_bitmapwidth) || dst_ystart > static_cast<int>(dst_bitmapheight))
        return;

    //limit to the smallest width/height
    uint dstartx = std::max<int>(dst_xstart, 0);
    uint dstarty  = std::max<int>(dst_ystart, 0);
    uint dendx = std::min<int>(dst_xstart+width,dst_bitmapwidth);
    uint dendy = std::min<int>(dst_ystart+height,dst_bitmapheight);

    uint sstartx = std::max<int>(src_xstart, 0);
    uint sstarty = std::max<int>(src_ystart, 0);
    uint sendx = std::min<int>(src_xstart+width,src_bitmapwidth);
    uint sendy = std::min<int>(src_ystart+height,src_bitmapheight);

    //start is greater than end
    if(sstarty > sendy || dstarty > dendy)
        return;

    //Alpha Blending
    //((srccolor * alpha) + (dstalpha * (256-alpha)) / 255 (src/dst/alpha value range: 0-255)
    //((srccolor * alpha) + (dstalpha * (257-alpha)) / 256 (src/dst/alpha value range: 1-256)

    //x >> 8 = x / 256
    //=>  (((srccolor+1) * (alpha+1)) + ((dstalpha+1) * (257 - (alpha+1))) >> 8 = 1..256
    //=> ((((srccolor+1) * (alpha+1)) + ((dstalpha+1) * (257 - (alpha+1))) >> 8) - 1 = 0..255

    //dst/src width and height
    uint dxw = dendx-dstartx;
    uint sxw = sendx-sstartx;
    uint dyh = dendy-dstarty;
    uint syh = sendy-sstarty;

    //width/height of copy feld
    uint copyw = std::min(dxw,sxw);
    uint copyh = std::min(dyh,syh);

    //start coord.
    uint dx = dstartx;
    uint sx = sstartx;
    uint dy = dstarty;
    uint sy = sstarty;

    //to reckon with integer
    int intAlpha = static_cast<int>(alpha);

    //copy as RGB/RGBA
    size_t bpp = std::min(src_bytepp,dst_bytepp);

    //not blendeffect and have same bytepp
    if(!blend && src_bytepp == dst_bytepp){
        while(copyh-- > 0){
            //Source Pixel index
            size_t spi = (sstartx + sy * src_width)*src_bytepp;
            //Destination Pixel index
            size_t dpi = (dstartx + dy * dst_width)*dst_bytepp;

            //copy the whole width
            memcpy(dst_data+dpi,src_data+spi,copyw*dst_bytepp*sizeof(ubyte));

            dy++;
            sy++;
        }
    }else if(src_bytepp == dst_bytepp){ //have same bytepp
        while(copyh-- > 0){
            //Source Pixel index
            size_t spi = (sstartx + sy * src_width)*src_bytepp;
            //Destination Pixel index
            size_t dpi = (dstartx + dy * dst_width)*dst_bytepp;

            ubyte *dest = dst_data+dpi;
            ubyte const *src = src_data+spi;

            //copy the whole width with alphablending
            size_t len = copyw*dst_bytepp*sizeof(ubyte);
            while (len-- > 0){
                //value range is over 255 (convert to int)
                int sa = static_cast<int>(*src)+1;
                int da = static_cast<int>(*dest)+1;

                //alpha blending color
                int32 color = (sa * intAlpha) + (da * (257-intAlpha));
                color = (color >> 8) - 1;

                *dest = static_cast<ubyte>(color);

                dest++;
                src++;
            }

            dy++;
            sy++;
        }
    }else{
        uint resetcopyw = copyw; //copy of copyw

        while(copyh-- > 0){
            copyw = resetcopyw;
            while(copyw-- > 0){
                //Source Pixel index
                size_t spi = (sx + sy * src_width)*src_bytepp;
                //Destination Pixel index
                size_t dpi = (dx + dy * dst_width)*dst_bytepp;

                ubyte *dest = dst_data+dpi;
                ubyte const *src = src_data+spi;

                if(src_bytepp == 3){ //is RGB (without alpha)
                    size_t len = src_bytepp;

                    //without alphablending
                    while(len-- > 0){
                        *dest++ = *src++;
                    }
                }else{
                    //copy as RGB/RGBA
                    size_t len = bpp;
                    while(len-- > 0){
                        //value range is over 255 (convert to int)
                        int sa = static_cast<int>(*src)+1;
                        int da = static_cast<int>(*dest)+1;

                        //alpha blending color
                        int32 color = (sa * intAlpha) + (da * (257-intAlpha));
                        color = (color >> 8) - 1;
                        *dest = static_cast<uint8>(color);

                        dest++;
                        src++;
                    }
                }
                sx++;
                dx++;
            }
            sy++;
            dy++;
        }
    }
}


Beispiel:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
blt_image(src_data,
          0,0,512,
          4,
          473,332,

          dst_data,
          0,0,1024,
          4,
          488,536,

          200,300,
          true,196);

src_data hat ein größe von [512*512*4] (2er potenz array),
das Bild darin ist 480x320 pixel größ.
dst_data hat ein größe von [1024*1024*4] (2er potenz array),
das Bild darin ist 640x512 pixel größ.
Der Bereich (0,0,200,300) wir dann in die Ziehl Bitmap kopiert, mit einer Transparenz(alpha) von 196.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »kiba« (26.06.2010, 17:12)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

24.06.2010, 15:33

Rein spontan ein paar Bemerkungen dazu:

Mach vielleicht lieber ein paar einzelne blit Funktionen als eine die alles kann, damit kannst du dir sicher erstmal einige ifs sparen und in weiterer Folge auch spezieller optimieren.
Kannst du nicht irgendwie ohne das if um zu checken ob alpha < 1 ist auskommen? Solche ifs in performancekritischen inneren Schleifen sollte man so gut es geht vermeiden.
Die Berechnung für das Alphablending kann man evtl. mit einigen Bitshifttricks optimieren (deine Pixel sind 32bit breit, d.h. man kann da evtl. irgendwie einen ganzen Pixel als einen int auffassen und dann mit Integerarithmetik alle Kanäle gleichzeitig blenden).
Wenn du noch mehr rausholen willst dann solltest du auf SSE setzen.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

3

25.06.2010, 07:49

Welcher Part ist denn zu langsam? Klar kann man mit diversen Standardoptimierungen draufballern (Loops aufrollen, unnötige If-Anweisungen, Bittricks, SIMD, ...). Allerdings bringt es im Normalfall überhaupt nichts präventiv zu optimieren, mess das Teil durch und schau wo tatsächlich Bottlenecks sind. Ansonsten optmimierst du ggf so toll das der Code wesentlich langsamer wird als das "unoptimierte" Orginal.
@D13_Dreinig

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

25.06.2010, 08:21

Also wie schon gesagt wurde:

C-/C++-Quelltext

1
2
3
4
5
                //is src_alpha < 1
                if(bpp >= 4){
                    if(src_data[spi+3] < 1)
                        continue;
                }


Der Ausdruck "bpp >= 4" ist schon vor der Schleife bekannt und wird sich währenddessen nicht mehr ändern!
Also sollte man ihn rausziehen und verschiedene Schleifen betreten, je nach dem ob der Ausdruck "true" oder "false" ist.

< 1 ist doch dasselbe wie == 0, oder nicht? In diesem Zusammenhang jedenfalls. Dann schreib das auch so hin, könnte schneller gehen. Denn bei < 1 wird der Compiler vermutlich Code generieren, um das entsprechende Byte aus einem DWORD rauszuholen und dann zu vergleichen. Bei == 0 könnte er mit einer Bitmaske direkt testen.

Wenn du das "if" drinlassen willst, dann vereinige beide zu "if(bpp >= 4 && src_data[spi + 3] == 0)". Der rechte Teil wird eh automatisch nur dann ausgewertet, wenn der linke "true" ergab.

Außerdem willst du vielleicht die ganze Blending-Berechnung überspringen, wenn der Alphawert = 255 ist, und dann direkt die Farbe rüberkopieren.

Dann fällt mir hier noch was zu ein:

C-/C++-Quelltext

1
2
3
4
                //Source Pixel index
                size_t spi = (sx + sy * src_width)*src_bytepp;
                //Destination Pixel index
                size_t dpi = (dx + dy * dst_width)*dst_bytepp;


Diese Berechnungen werden für jedes Pixel gemacht!
Aber in 99% der Fälle würde es reichen, einfach ++spi und ++dpi zu machen.
Also erzeuge die beiden Variablen außerhalb der Schleifen und erhöhe sie passend (also innerhalb einer Zeile mit ++, am Ende einer Zeile ein bisschen mehr, so dass sie auf den Anfang der nächsten Zeile zeigen).
Vielleicht auch Zeiger benutzen statt Indizes!

PS: Vielleicht eine gute Idee für einen Geschwindigkeits-Contest? :P

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

5

25.06.2010, 10:21

Das wird vermutlich ehh alles nichts bringen, da der Speicherzugriff der Bottleneck sein wird. Das einzig sinnvolle ist es, das auf die GraKa auszulagern und diese Funktionen in Shadern zu implementieren.

Crush

Alter Hase

Beiträge: 383

Wohnort: Stuttgart

Beruf: Softwareentwickler

  • Private Nachricht senden

6

25.06.2010, 11:07

Die Multiplikationen wirst Du mit linken Bitshifts nochmal deutlich schneller hinbekommen.

kiba

Alter Hase

  • »kiba« ist der Autor dieses Themas

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

7

26.06.2010, 18:40

Hab den Code noch mal geändert
Ich weiß aber nicht wie ich die Formel vereinfachen könnte.
Wenn z.b. der Alpha Wert des Pixels 255 ist , dann muss ich die Pixel einfach kopieren ohne diese zu berechnen
(Aber das bringt dann ja ein if mehr in die Schleife)

Und die Multiplikationen mit bitshifts zu machen, wie soll das gehen
ich kann ja nur mit 2er Potenzen muliplizien/dividieren.

Habs mal getestet...
kein blending: 0.4 milisec
Mit Blending oder (Src als)RGBA Bild: 12 milisec.

Wenn ich das mit einfachen for-Scheifen und jedes Pixels kopiere....
kein blending: 14 milisec
Mit Blending oder (Src als)RGBA Bild: 21 milisec.

Mit den SDL Functionen
Normales Blt: 0.9 milisec
Mit Alpha setzen und Blt: 14 milisec

Werbeanzeige