1 Ostatnio edytowany przez Tomasz Wachowiak (2015-02-23 21:56:56)

Zgodnie z obietnicą wrzucam trójkąta na blitterze. Można pokombinować z flagą "blitMode" - 0 oznacza tryb HOG, 1 - tryb współdzielenia szyny (dzięki sprytnemu restartowaniu blittera i tak mamy 90% szybkości trybu HOG). Wypełnienie trójkąta o współrzędnych 0,0 -> 319,199 -> 0,199 zajmuje około 30% czasu ramki.

Post's attachments

btriang1.zip 4.68 kb, liczba pobrań: 10 (od 2015-02-23) 

Tylko zalogowani mogą pobierać załączniki.

2 Ostatnio edytowany przez mkm (2015-02-24 08:51:55)

Fajnie:) Mam nadzieję, że w przyszłym tygodniu będę miał trochę czasu by zerknąć dokładniej w kod i go przeanalizować. Z tego co widziałem to jest scan line fill, gdzie wyznaczać X1,x2 dla Y'ków i rysujesz H line blitter'em, tak?
Ciekawi mnie czy robiłeś porównanie cpu / blitter dla różnych trójkątów? Robiłem podobny eksperyment kiedyś i dla dużych trójkątów było znacznie szybciej blitter'em, ale już przy małych trójkątach (które są bardziej życiowe o obiektach 3d) inicjalizacja blitter'a była bardziej kosztowna niż zysk z jego prędkości ponad cpu i bardziej opłacało mi się używać cpu dla takich sytuacji. Testy był robiony na szybko więc pewnie dało się tą inicjalizację zrobić szybciej i zniwelować efekt. Ciekaw jestem Twoich odczuć i czy robiłeś takie porównania praktyczne? (nie chodzi mi o teoretyczne timingi)

Maciek
--------
Atari 65XE + Ultimate 1MB + Stereo + SIO2SD | Atari 520STE + 4MB + UltraSatan | Atari Falcon 030 + CT60e + 14MB ST + 256MB TT + 68882  + CF + Netusbee | Amiga 500 + 1MB + Gotek | Amiga 600 + 2MB Chip + 8MB Fast + CF

3 Ostatnio edytowany przez Tomasz Wachowiak (2015-02-24 10:03:52)

mkm napisał/a:

Fajnie:) Mam nadzieję, że w przyszłym tygodniu będę miał trochę czasu by zerknąć dokładniej w kod i go przeanalizować. Z tego co widziałem to jest scan line fill, gdzie wyznaczać X1,x2 dla Y'ków i rysujesz H line blitter'em, tak?

Dokładnie tak.. :D

mkm napisał/a:

Ciekawi mnie czy robiłeś porównanie cpu / blitter dla różnych trójkątów? Robiłem podobny eksperyment kiedyś i dla dużych trójkątów było znacznie szybciej blitter'em, ale już przy małych trójkątach (które są bardziej życiowe o obiektach 3d) inicjalizacja blitter'a była bardziej kosztowna niż zysk z jego prędkości ponad cpu i bardziej opłacało mi się używać cpu dla takich sytuacji. Testy był robiony na szybko więc pewnie dało się tą inicjalizację zrobić szybciej i zniwelować efekt. Ciekaw jestem Twoich odczuć i czy robiłeś takie porównania praktyczne? (nie chodzi mi o teoretyczne timingi)

Spróbujemy jednak teoretycznie na początek, ok? :P Nadmiarowy kod dla blittera to:

    asr.w    #3,d3
    move.w    d1,endmsk1(a6)
    move.l    d4,xCount(a6)
    move.b    #$a0,lineNum(a6); HOG

w przypadku linii poniżej 16 pikseli i

    asr.w    #3,d3  ;8+6
    addq.w    #1,d3  ;4
                   
    swap    d3   ;4
    move.w    d5,d3  ;4

    move.w    d0,endmsk1(a6)  ;12
    move.w    d1,endmsk3(a6)  ;12
    move.l    d3,xCount(a6)     ;16
                   
    move.b    #$a0,lineNum(a6); HOG   16

w przypadku linii powyżej 16 pikseli.

Mamy więc 82 cykle na odpalenie blittera.

Na motorli dochodzi wyliczenie skoku do właściwej długości linii i sam skok. Coś takiego:

        move.l    linesAdr(a4,d3.w),a5  ;20
    jmp        (a5)  ; 8

       and.w   d0,d2   ; maski w linii pierwszej wypełniającej   +4
       and.w   d1,d3  ; maski w linii ostatniej wypałniającej     +4

Rejestry są z czapy, chodzi o wyliczenia :)

Odejmując wszystko wychodzi, że inicjalizacja blittera zabiera o 46 cykle więcej, a to jest  w przybliżeniu 4  "move.w d0,i(a6)" - wypełniania na motoroli. To daje 4*16 = 64 piksele. Tyle w najlepszym przypadku zdąży narysować motorola, zanim blitter weźmie się do pracy. Czyli gdzieś po 80-100 blitter dogoni motorolkę.

Zmiana wypełniania z blittera na motorolkę jest w sumie banalna, więc można sobie napisać procedurę i zobaczyć, czy wyliczenia się potwierdzą. :)

Wydaje mi się, że 1-bitplanowe trójkąty wykorzystuje się jednak do wypełniania prostych (i dużych) figur, bo jeśli chcemy mieć skomplikowany obiekt (który prawdopodobnie nie zmieści się jednej ramce), to warto rozważyć użycie wieloplanowego wypełniania, żeby obiekt odpowiednio pokolorować.

Blitterem można wypełnić kilka polygonów na raz, co powoduje że przy bardziej skomplikowanych scenach (więcej niż jedna bryła), praktycznie zawsze będzie wydajniejszy od CPU.

Atari: FireBee, (Falcon030 CT60e SuperVidel SvEthlana CTPCI), TT, (520ST Pak030 Frak PuPla Panther), (520ST 4MB ST RAM 8MB TT RAM CosmosEx SC1435), (1040STFM UltraSatan SM124), (1040STE 4MB ST RAM 8MB TT RAM CosmosEx NetUSBee SM144 SC1224), 260ST, 520 ST+, (MEGA ST SM125), (65XE Rapidus U1MB VBXE SIDE2 SIO2PC), (Jaguar SkunkBoard), Lynx II, 2x Portfolio

5

@Wachu no właśnie miałem podobne obserwacje, aż moje face'y miały relatywnie krótkie linie to nie widziałem ogólnie zysku ze scan line fill na bliterze. przy duuuuzych face'a racja zysk będzie dokładnie jak to udowodniłeś.

@Adam blitterem można wypełniać kilka obiektów na raz ale nie scan line fill'em tylko eor fill'em. technika jest tu inna. no ale wtedy blitter musi czytać i zapisywać dane przez co działa wolniej. ale jest inicjalizowany raz i tak jak mówisz wypełniasz całą scenę "na raz". wszystko ma swoje wady i zalety:) dodatkowo eor fill'em dostajesz bonus wypełniania obiektów niewypukłych.

Maciek
--------
Atari 65XE + Ultimate 1MB + Stereo + SIO2SD | Atari 520STE + 4MB + UltraSatan | Atari Falcon 030 + CT60e + 14MB ST + 256MB TT + 68882  + CF + Netusbee | Amiga 500 + 1MB + Gotek | Amiga 600 + 2MB Chip + 8MB Fast + CF
Adam Klobukowski napisał/a:

Blitterem można wypełnić kilka polygonów na raz, co powoduje że przy bardziej skomplikowanych scenach (więcej niż jedna bryła), praktycznie zawsze będzie wydajniejszy od CPU.

Jestem zaintrygowany... W jaki sposób?

mkm napisał/a:

@Wachu no właśnie miałem podobne obserwacje, aż moje face'y miały relatywnie krótkie linie to nie widziałem ogólnie zysku ze scan line fill na bliterze. przy duuuuzych face'a racja zysk będzie dokładnie jak to udowodniłeś.

:D

mkm napisał/a:

@Adam blitterem można wypełniać kilka obiektów na raz ale nie scan line fill'em tylko eor fill'em. technika jest tu inna. no ale wtedy blitter musi czytać i zapisywać dane przez co działa wolniej. ale jest inicjalizowany raz i tak jak mówisz wypełniasz całą scenę "na raz". wszystko ma swoje wady i zalety:) dodatkowo eor fill'em dostajesz bonus wypełniania obiektów niewypukłych.

Macie gdzieś jakieś materiały o tym?

8 Ostatnio edytowany przez mkm (2015-02-24 10:24:00)

Tomasz Wachowiak napisał/a:

Macie gdzieś jakieś materiały o tym?

Rysujesz sam obrys trojkat'a. Nie linie tylko obrys tak by mieć dla każdego X dokładnie dwa punkty Y1, Y2 zapalone na ekranie. Potem robiś EOR każdej linii z linia-1. i masz wypełniony cały blitowany obszar nie zaleznie ile obrysów i i lle face'ów tam masz. czas jest stały - czasem to dobrze a czasem to źle;) Wady: blitter musi czytac i zapisywać dane przez co działa wolniej, jesli masz mało face'ów ale na wielu bitplanach to pewnie wyjdzie wolniej. Jeśli masz dużo małych face'ów np. na 2 planach to może wyjść fajnie.

Maciek
--------
Atari 65XE + Ultimate 1MB + Stereo + SIO2SD | Atari 520STE + 4MB + UltraSatan | Atari Falcon 030 + CT60e + 14MB ST + 256MB TT + 68882  + CF + Netusbee | Amiga 500 + 1MB + Gotek | Amiga 600 + 2MB Chip + 8MB Fast + CF

Wachu: wygogluj eor fill. Chwile zajęło mi zrozumienie jak to działa, ale MKM mi dopomógł :)

Atari: FireBee, (Falcon030 CT60e SuperVidel SvEthlana CTPCI), TT, (520ST Pak030 Frak PuPla Panther), (520ST 4MB ST RAM 8MB TT RAM CosmosEx SC1435), (1040STFM UltraSatan SM124), (1040STE 4MB ST RAM 8MB TT RAM CosmosEx NetUSBee SM144 SC1224), 260ST, 520 ST+, (MEGA ST SM125), (65XE Rapidus U1MB VBXE SIDE2 SIO2PC), (Jaguar SkunkBoard), Lynx II, 2x Portfolio

Kurcze. Dzisiaj napiszę sobie to wypełnianie na Motoroli. Wydaję mi się, że zbyt optymistycznie podszedłem do samej prędkości blittera. Wyliczenia są raczej dobre, ale chyba warto sprawdzić to (jak pisał MKM) w praktyce.

11

z tego co widzę to masz parę rejestrów adresowych wolnych.
tak więc, tutaj mógłbyś przypisać każdej masce osobny An i zejść z 24 do 16 cykli:

                    move.w    d0,endmsk1(a6)        ;first line mask
                    move.w    d1,endmsk3(a6)        ;last line mask

tutaj również dedykowany An, dodatkowo nie ma potrzeby zmiany yCount, więc zamiast Longa możesz zapisać Word:

                    move.l    d3,xCount(a6)        ;xcount = d3, ycount = 1 at once

czyli zamiast 16 mamy 8 cykli

tu również dedykowany An:

                    move.b    #$a0,lineNum(a6); HOG   16

zamiast 16 mamy 12 cykle


Czyli z 82 cykli inicjalizacji mógłbyś zejść do 62.

Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org
Cyprian napisał/a:

z tego co widzę to masz parę rejestrów adresowych wolnych.
tak więc, tutaj mógłbyś przypisać każdej masce osobny An i zejść z 24 do 16 cykli:

                    move.w    d0,endmsk1(a6)        ;first line mask
                    move.w    d1,endmsk3(a6)        ;last line mask

tutaj również dedykowany An, dodatkowo nie ma potrzeby zmiany yCount, więc zamiast Longa możesz zapisać Word:

                    move.l    d3,xCount(a6)        ;xcount = d3, ycount = 1 at once

czyli zamiast 16 mamy 8 cykli

tu również dedykowany An:

                    move.b    #$a0,lineNum(a6); HOG   16

zamiast 16 mamy 12 cykle


Czyli z 82 cykli inicjalizacji mógłbyś zejść do 62.

W rzeczywistym kodzie zostaje mi jeden wolny rejestr adresowy :(, a yCount MUSI być inicjalizowany co blitta. Jednak masz rację, że z 8-12 cykli dało by się w tym kodzie jeszcze urwać.

13 Ostatnio edytowany przez Cyprian (2015-02-24 14:29:36)

faktycznie masz rację z yCount. 
Ale możesz zamienić xCount z yCount (czyli również Destination X increment oraz Destination y increment) dzięki temu xCount będzie tylko raz inicjowany a yCount przed każdym blitem.
Takie rozwiązanie zastosowałem w mojej procedurze dla sprajtów:

;BLiTTER Init
    move.l    #$00020002,(A0)+        ; source X increment / source Y increment
    move.l    A2,(A0)+            ; source address
    move.l    #-1,(A0)+            ; mask 1 /2
    move.w    #-1,(A0)+            ; mask 3
    move.l    #$00080080,(A0)+        ; destination X increment / destination Y increment
    lea        2(A0),A4            ; remember source destination
    move.l    A3,(A0)+            ; destination address
    move.w    #$0005,(A0)+        ; count X surface
    movea.l    A0,A1                ; remember count Y surface
    move.w    D0,(A0)+            ; count Y surface
    move.w    #$0204,(A0)+        ; HOP / LOP
    move.w    D4,(A0)                ; BUSY / HOG / SMUDGE / LINE NUMBER // FXSR / NFSR / SKEW


; Copy MaskSprite to Screen
    move.b    D2,(A0)                ; start blitter

    REPT    3
        lea        2(A3),A3
        move.w    A3,(A4)            ; destination address
        move.w    D0,(A1)            ; count Y surface
        move.b    D2,(A0)            ; start blitter
    ENDR

;
;BLITTER RE-INIT Sprite to Screen
    lea        $FFFF8A3C.w,A0
    move.l    A5,A3
    move.w    #$0207,$FFFF8A3A.w        ; HOP / LOP

; Copy Sprite to Screen
    move.w    A3,(A4)                ; destination address
    move.w    D0,(A1)                ; count Y surface
    move.b    D2,(A0)                ; start blitter

    REPT    3
        lea        2(A3),A3
        move.w    A3,(A4)            ; destination address
        move.w    D0,(A1)            ; count Y surface
        move.b    D2,(A0)            ; start blitter
    ENDR
Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org
Cyprian napisał/a:

faktycznie masz rację z yCount. 
Ale możesz zamienić xCount z yCount (czyli również Destination X increment oraz Destination y increment) dzięki temu xCount będzie tylko raz inicjowany a yCount przed każdym blitem.
Takie rozwiązanie zastosowałem w mojej procedurze dla sprajtów:

;BLiTTER Init
    move.l    #$00020002,(A0)+        ; source X increment / source Y increment
    move.l    A2,(A0)+            ; source address
    move.l    #-1,(A0)+            ; mask 1 /2
    move.w    #-1,(A0)+            ; mask 3
    move.l    #$00080080,(A0)+        ; destination X increment / destination Y increment
    lea        2(A0),A4            ; remember source destination
    move.l    A3,(A0)+            ; destination address
    move.w    #$0005,(A0)+        ; count X surface
    movea.l    A0,A1                ; remember count Y surface
    move.w    D0,(A0)+            ; count Y surface
    move.w    #$0204,(A0)+        ; HOP / LOP
    move.w    D4,(A0)                ; BUSY / HOG / SMUDGE / LINE NUMBER // FXSR / NFSR / SKEW


; Copy MaskSprite to Screen
    move.b    D2,(A0)                ; start blitter

    REPT    3
        lea        2(A3),A3
        move.w    A3,(A4)            ; destination address
        move.w    D0,(A1)            ; count Y surface
        move.b    D2,(A0)            ; start blitter
    ENDR

;
;BLITTER RE-INIT Sprite to Screen
    lea        $FFFF8A3C.w,A0
    move.l    A5,A3
    move.w    #$0207,$FFFF8A3A.w        ; HOP / LOP

; Copy Sprite to Screen
    move.w    A3,(A4)                ; destination address
    move.w    D0,(A1)                ; count Y surface
    move.b    D2,(A0)                ; start blitter

    REPT    3
        lea        2(A3),A3
        move.w    A3,(A4)            ; destination address
        move.w    D0,(A1)            ; count Y surface
        move.b    D2,(A0)            ; start blitter
    ENDR

Pamiętaj Cyprian, że xCount wraz ze wzrostem/skróceniem długości linii zwiększa się lub zmniejsza i trzeba reagować na bieżąco. :) Przy blicie spritea faktycznie można xCounta raz ustawić.
P.S. Piękny kod swoją drogą, wszystko z minimalną ilością cykli. :)

15 Ostatnio edytowany przez Cyprian (2015-02-24 15:40:19)

no tak, ale możesz dać albo:

  xCount = 40 / yCount = 1

albo:

  xCount = 1 / yCount = 40

z tego co pamiętam efekt jest ten sam operacja dokonywana jest na tych samych 40stu słowach.
Oczywiście w zależności od wariantu trzeba odpowiednio ustawić Destination X/Y increment.

---edycja---

przemyślałem to jeszcze raz,  w wariancie xCount = 1 może być problem z zastosowaniem EndMask

Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org

16 Ostatnio edytowany przez Tomasz Wachowiak (2015-02-24 15:51:42)

Cyprian napisał/a:

no tak, ale możesz dać albo:

  xCount = 40 / yCount = 1

albo:

  xCount = 1 / yCount = 40

z tego co pamiętam efekt jest ten sam operacja dokonywana jest na tych samych 40stu słowach.
Oczywiście w zależności od wariantu trzeba odpowiednio ustawić Destination X/Y increment.

Hehehe. A tego to nie wiedziałem. Jak widać zawsze można się czegoś nowego dowiedzieć. :D

Edit: Wystarczy wyjść, stanąć obok i spojrzeć z innej strony. :P Faktycznie wystarczy zmienić x na y i powinno działać.

17

w międzyczasie wyedytowałem posta:
przemyślałem to jeszcze raz,  w wariancie xCount = 1 może być problem z zastosowaniem EndMask

Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org
Cyprian napisał/a:

w międzyczasie wyedytowałem posta:
przemyślałem to jeszcze raz,  w wariancie xCount = 1 może być problem z zastosowaniem EndMask

Hahahhaa :D A ja już się z tobą w międzyczasie zgodziłem. Masek nie rozważałem.

19

i jeszcze coś mi wpadło do głowy. Czy faktycznie poniższa instrukcja jest potrzebna?

   move.w    d5,d3  ;4

"addq.w    #1,d3  ;4" robisz w obrębie Word a nie Long

Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org
Cyprian napisał/a:

i jeszcze coś mi wpadło do głowy. Czy faktycznie poniższa instrukcja jest potrzebna?

   move.w    d5,d3  ;4

"addq.w    #1,d3  ;4" robisz w obrębie Word a nie Long

Pamiętaj, że po tych operacjach w d3 jest trzymany i xCount i yCount.

21

Panowie, bardzo proszę o poprawienie cytatów zgodnie z regulaminem. Tego się czytać nie da. Timer 24h.

Czy możecie wyjaśnić, Stirlitz, dlaczego wasz służbowy adres stirlitz@rsha.gov.de ma aliasa justas@gru.su?
Nie czytam PM. Proszę używać e-mail.

22

Ostatnio odbył się kompot z produkcjami na 1bitplan (na ST). Może będzie kolejny. Wtedy z 1bitplanowym fillerem będziecie do przodu :).

23

Tomasz Wachowiak napisał/a:

P.S. Piękny kod swoją drogą, wszystko z minimalną ilością cykli. :)

a dzięki :)

Bober napisał/a:

Ostatnio odbył się kompot z produkcjami na 1bitplan (na ST). Może będzie kolejny. Wtedy z 1bitplanowym fillerem będziecie do przodu :).

ten filler można zastosować również do wielu bitplanów

Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org