[#1] Blitter pipeline
Natknąłem się na ciekawy problem, który najprawdopodobniej ma przyczynę w tym, że Blitter jest procesorem potokowym (pipeline) i zapis danych do kanału D następuje dopiero w drugim cyklu jego pracy.

Udało mi się znaleźć fenomenalny artykuł nt. Blittera w Internecie, w czasopiśmie "Amiga World Tech Journal", z października 1991 roku.

Jest to wyczerpujący artykuł nt. tego koprocesora Amigi. Opisuje również zagadnienie rejestru potoku.

Otóż problem polega na tym, że mam BOBa, który ma 32 piksele szerokości i chcę zapamiętywać tło, które się pod nim znajduje. Chcę wykorzystać do tego bufor o szerokości również 32 piksele.

Jak wiadomo, jeśli rysuję na przecięciu słów, to muszę dodać 1 słowo więcej do szerokości operacji. Jednakże BOB ma szerokość 32 piksele (2 słowa), więc pomieszczę tło w buforze, ale muszę odpowiednio je przesunąć i wyciąć.

Maska A jest stała i wynosi 0xffff, zaś rejestry BLTAFWM i BLTALWM są ustawiane prawidłowo, by wycinały odpowiedni fragment.

Ponieważ muszę przesunąć grafikę tak, by dosunięta była do słowa (by zmieściła się w buforze), mogę przesunąć ją w prawo do następnego słowa w wierszu.

Ustawiam zatem źródło B na pierwsze słowo grafiki, zaś cel C i D na słowo poprzedzające bufor.

Jednakże ponieważ rozmiar operacji jest o 1 słowo większy, muszę odpowiednio zmienić modulo, tj. ustawić modulo kanału C i D na -2.

Jako rodzaj operacji ustawiam cookie-cut (0xca), czyli AB + aC, ponieważ chcę, by w miejsca gdzie A jest wyzerowane zostały wstawione aktualne dane z bufora.

Blitowanie jednak przy tych ustawieniach powoduje, że każde ostatnie słowo wiersza bufora (prócz ostatniego) jest nadpisywane (przez poprzednią zawartość - sprzed zapisu), mimo, że nie powinno (bo maska tam jest wyzerowana i powinna być tam wstawiona aktualna zawartość bufora, czyli inaczej mówiąc - nic nie powinno być nadpisywane).

To naprawdę powinno działać. Wstawiana jest jednak stara zawartość bufora, a nie nowa, zapisana dopiero co przez Blitter. Prawdopodobnie zapis do D następuje za późno ze względu na rejestr potoku.

Wygląda na to, że ze względu na to, trzeba zrealizować to inaczej. Artykuł na pewnym przykładzie podaje rozwiązanie.

Na szczęście ten artykuł opisuje wyczerpująco zagadnienie pracy z Blitterem. Jestem jeszcze w trakcie lektury. Jeśli znajdę rozwiązanie, to się nim podzielę.

Cały problem nie występowałby, gdybym użył bufora na tło o szerokości o jeden większej niż szerokość BOBa, ale chciałbym mimo to dowiedzieć się jak zrobić to w ten sposób. Jakby co, zrobię dla świętego spokoju ten bufor szerszy o to jedno słowo.

Artykuł podaje rozwiązanie na takie i inne problemy w programowaniu Blittera.

Podaję link do pisma w PDF: https://the-eye.eu/public/Books/computerarchive.org/amigaworld%20tech%20journal/Amiga_World_Tech_Journal_Vol_01_04_1991_Oct.pdf

Ostatnia aktualizacja: 22.07.2018 16:26:11 przez Hexmage960
[#2] Re: Blitter pipeline

@Hexmage960, post #1

Naciąłem się na to samo i swojego czasu o tym pisałem - objawiało się to głównie przy funkcji składającej tekst z pojedynczych znaków. Spędziłem nad tym nie godziny tylko wręcz miesiące i rozwiąznia nie widzę, więc albo tu jest granica moich zdolności poznawczych albo to jest bug/quirk hardware'u.

Teraz problem mnie nie dotyczy bo robię odpowiednio większe bufory. Zapisywanie tła robię na większym o słowo na operacji D:=A bez shiftów, bo jest szybsza niż cookie cut.

Tak czy inaczej trzymam kciuki, że rozwiążesz ten problem za nas obu. ;)

EDYT: to co zalinkowałeś faktycznie może mieć z tym związek. Pozwolę sobie to tu zacytować gdyby link kiedyś padł:

PIPELINE REGISTER

For enhanced performance, the Blitter is pipelined. You might expect the Blitter to read all of the sources for the first cycle, then write the computed value to the destination, then read the sources for the second cycle, then write the com puted value to the destination, and so on. Actually, it writes the value computed in the first cycle after reading the sources for the second cycle—no write takes place in the first cycle, and an extra write takes place after the Blitter is finished. This is useful information to know if you are trying to do something like find the bitwise exclusive OR of a large sec tion of memory. For instance, if you wanted to find the bit wise exclusive OR of an array of 1000 16-bit words, you might try setting the A channel to point to the beginning of the ar ray, and the C and D channels to point to the second word, then set the height to 999 and the width to 1 (word), and use a function of A-C+-AC. The thinking would be along the lines of:

for (i=0; i<999; i++)
	a[i+1] ^= a[i];
return a[999];


Unfortunately, the pipeline register will cause the "desti nation" to be written too late. The solution is to set the C and D channels to point to the third word, set the height to 998, and exclusive OR the last two by hand. This will work, and corresponds to the code:

for (i=0; i<998; i++)
	a[i+2] = a[i];
return a[999] ^ a[998];



Ten program blitlab jest gdzieś dostępny?

Ostatnia aktualizacja: 22.07.2018 17:32:54 przez teh_KaiN
[#3] Re: Blitter pipeline

@teh_KaiN, post #2

Miałem jeszcze raz edytować ale nie dałem rady: jest, nawet ze źródłami. Może jakoś niedługo ugryzę ten temat jeszcze raz. A tu jest coś nowszego.

Ostatnia aktualizacja: 22.07.2018 17:34:59 przez teh_KaiN
[#4] Re: Blitter pipeline

@teh_KaiN, post #2

Naciąłem się na to samo i swojego czasu o tym pisałem - objawiało się to głównie przy funkcji składającej tekst z pojedynczych znaków. Spędziłem nad tym nie godziny tylko wręcz miesiące i rozwiąznia nie widzę, więc albo tu jest granica moich zdolności poznawczych albo to jest bug/quirk hardware'u.

Ja drugi raz spotykam się z tym zagadnieniem i również spędziłem dużo czasu go rozwiązując.

To nie jest bug, tylko optymalizacja hardware. Dzięki potokowi Blitter może wykonywać wiele zadań równocześnie.

Jeśli podczas blitowania Blitter pobiera dane zapisane przez niego w ostatnim cyklu, to nie pobierze nam tych zapisanych danych. Dostaniemy dane przed tym zapisem.

Problem bardzo przypomina mi próby zapisania kodu kiedy procesor ma pamięć "cache".

Teraz problem mnie nie dotyczy bo robię odpowiednio większe bufory. Zapisywanie tła robię na większym o słowo na operacji D:=A bez shiftów, bo jest szybsza niż cookie cut.

Tak czy inaczej trzymam kciuki, że rozwiążesz ten problem za nas obu. ;)

Rozwiązań nasuwa się kilka (m.in. nawiązując do tego fragmentu artykułu).

Można kombinować z blitem. Ja jednak ustawię ten bufor szerszy, bo to najprostsze rozwiązanie.

Ostatnia aktualizacja: 22.07.2018 18:23:55 przez Hexmage960
[#5] Re: Blitter pipeline

@teh_KaiN, post #3

Ten program (blitlab) sprawdzałem już jakiś czas temu i choć fajny - ma troszkę toporny interfejs użytkownika (system 1.3).

Przy okazji wpadłem na inne rozwiązanie tego zagadnienia.

Za pomocą jednego blitu - to raczej tylko gdy bufor jest szerszy. I to jest bardzo dobre rozwiązanie.

Ale można również podzielić w sprytny sposób jeden blit na dwa bez dodatkowych kosztów (sumaryczny rozmiar operacji jest taki sam). Ponieważ najlepiej przesuwa się w tym przypadku dane w lewo (bo chcemy dosunąć do początku słowa), warto użyć trybu Descending.

Trybu Descending używamy na całym obiekcie bez ostatniej 16-bitowej kolumny. Ostatnią kolumnę blitujemy za pomocą drugiej operacji Ascending i odpowiedniego przesunięcia w prawo łącząc z poprzednim blitem za pomocą operacji OR.

Zaletą tego drugiego rozwiązania jest prawdopodobnie również to, że można blitować z absolutnie dowolną maską. Kiedyś coś robiłem w tej kwestii ale do tego rozwiązania nie doszedłem.

Ostatnia aktualizacja: 22.07.2018 19:22:36 przez Hexmage960
[#6] Re: Blitter pipeline

@Hexmage960, post #5

Tutaj kawałek kodu, którego używam aktualnie do BOBów w mojej produkcji. Zastosowałem szerszy o słowo bufor do przechowywania tła.

Myślę, że kod jest całkiem elegancki i czytelny. Zastosowałem tylko stałe symboliczne również z <hardware/blit.h> (chyba że ustawiam na zero), no i wszystkie niezbędne dane są w zmiennych przed operacją. Jeśli ktoś chce wykorzystać kod u siebie - nie ma problemu.

Dane Bobów i bufor na tło są w standardowym formacie BitMap Amiga OS typu non-interleaved. Uwaga: bufor na tło musi być o słowo szerszy niż bitmapa BOBa (o czym wspomniałem wyżej).

Jest również funkcja generująca maskę. Maska musi mieć rozmiar jednego bitplanu o rozmiarze BOBa.

Jest jedna funkcja do zapamiętania i odtwarzania tła. Zamienia ona parametry blitu miejscami gdy chcemy odtworzyć tło (parametr op = RESTORE).

Wkleję tutaj plik "Blit.h".
#ifndef BLIT_H
#define BLIT_H

#ifndef EXEC_TYPES_H
#include <exec/types.h>
#endif /* EXEC_TYPES_H */

/* storeBack op parameter */
enum ops
    {
    STORE,
    RESTORE
    };

void prepBobMask(struct BitMap *bob, UBYTE *mask);
void blitBob(struct BitMap *bob, UBYTE *mask, struct BitMap *back, WORD x, WORD y);
void storeBack(struct BitMap *back, WORD x, WORD y, struct BitMap *store, UBYTE op);

#endif /* BLIT_H */


Ostatnia aktualizacja: 23.07.2018 04:24:10 przez Hexmage960
[#7] Re: Blitter pipeline

@Hexmage960, post #6

custom.bltsize = (bltsizv << HSIZEBITS) | bltsizh;

Kompilator się pewnie domyśli ale może lepiej przed pętlą zamiast trzymać bltsizv i bltsizh lepiej to wrzucić do jednej zmiennej i zrobić w pętli po prostu przypisanie.

Co do rozbicia na dwa blity to jednak bym był przeciwny, bo to wiąże się z czekaniem aż blitter skończy. Tak samo proponuję Ci przejść z klasycznego planara na interleaved, bo w ten sposób pozbędziesz się wielu WaitBlitów.

Możesz referencyjnie rzucić okiem na blitUnsafeCopyMask lub liczący bardzo podobnie do Twojego kodu mój system bobów.
[#8] Re: Blitter pipeline

@teh_KaiN, post #7

Kompilator się pewnie domyśli ale może lepiej przed pętlą zamiast trzymać bltsizv i bltsizh lepiej to wrzucić do jednej zmiennej i zrobić w pętli po prostu przypisanie.

Tak, zgoda. Akurat rozbiłem to na dwie zmienne bo Blitter ECS/AGA ma rejestry BLTSIZV i BLTSIZH. Dopiero teraz zorientowałem się, że żeby działało to na OCS muszę użyć BLTSIZE.

Co do rozbicia na dwa blity to jednak bym był przeciwny, bo to wiąże się z czekaniem aż blitter skończy. Tak samo proponuję Ci przejść z klasycznego planara na interleaved, bo w ten sposób pozbędziesz się wielu WaitBlitów.

Niewielką wadą interleaved jest to, że maska zajmuje 5 razy więcej miejsca przy 5 bitplanach. Wiem, że nadrabia to szybszymi blitami.

Co do rozbicia na dwa blity - zgadzam się. Zamiast tego, lepiej używać ciut szerszego bufora i uniwersalnej operacji D = A.

Tak się fajnie złożyło, że mój kod jest bardziej uniwersalny niż mi się wydawało.

Otóż operacja storeBack() w tej postaci może być używana z powodzeniem aż do 3 do innych rzeczy.

Może:
- Wycinać ikony (obiekty bez maski) z tła,
- Wklejać ikony w tło,
- Wycinać obrazy BOBów z tła.

Już opracowałem odpowiednie makra, które upraszczają wywoływanie.

Ostatnia aktualizacja: 23.07.2018 09:05:38 przez Hexmage960
[wyróżniony] [#9] Re: Blitter pipeline

@Hexmage960, post #1

Dodam do tego mojego wątku rozwiązanie tej zagadki.

Otóż rozdział o Pipeline Register (rejestr potoku) w Hardware Reference Manual wszystko wyjaśnia.

Cytuję:

"(...) What all this means is that the first two sets of sources are fetched
before the first destination is written."


Co oznacza w wolnym tłumaczeniu, że najpierw pobierane są dwa zestawy danych z kanałów źródłowych zanim nastąpi zapisanie tego pierwszego zestawu.

I to wyjaśnia dlaczego w rejestrach Blittera jest poprzednia zawartość tej pamięci. szeroki uśmiech
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem