kategorie: ANSI C, Asembler
[#1] [ASM] Szybki algorytm rysowania linii w ASM
Cześć,
Obecnie używam całkiem szybkiego algorytmu do rysowania linii (a właściwie tylko do rasteryzacji krawędzi do bufora)
testowałem kilka. Czy Ktoś zna/ma zoptymalizowany/szybki kod takiej funkcji w asm może? Asm jest poza moimi granicami,
byłem ciekawy wyniku. Mógłbym go wstawić jako funkcje ASM w C.

Obecnie używam takiego:
Ma niestety 3 If-y w pętli, ale używałem też takiego który nie miał żadnego i nie był szybszy..

void	GR_FV_Segment_To_Buffer(const int8 _buff_id, int32 x0, int32 y0, int32 x1, int32 y1)
{
	int32 dx = x1 - x0;
	int32 dy = y0 - y1;
	int32 e2;

	if (x0 < x1)
	{
		int32 dx = x1 - x0;
		int err = dx + dy;

		for (;;)
		{
			GR_fv_buf_x[_buff_id][y0] = x0;
			GR_fv_buf_x_cell_id[_buff_id][y0] = GR_fv_proxy_cell_id;

			if (x0 == x1 && y0 == y1) break;

			e2 = err << 1;

			if (e2 >= dy)
			{
				err += dy;
				x0++;
			}

			if (e2 <= dx)
			{
				err += dx;
				y0++;
			}
		}
	}
	else
	{
		int32 dx = x0 - x1;
		int err = dx + dy;

		for (;;)
		{
			GR_fv_buf_x[_buff_id][y0] = x0;
			GR_fv_buf_x_cell_id[_buff_id][y0] = GR_fv_proxy_cell_id;

			if (x0 == x1 && y0 == y1) break;

			e2 = err << 1;

			if (e2 >= dy)
			{
				err += dy;
				x0--;
			}

			if (e2 <= dx)
			{
				err += dx;
				y0++;
			}
		}
	}
}


Ostatnia aktualizacja: 13.08.2022 01:13:13 przez mateusz_s

Ostatnia aktualizacja: 13.08.2022 01:16:06 przez mateusz_s
[#2] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #1

Z asemblerem nie pomogę, bo to też nie mój język, ale chyba można z C wycisnąć trochę więcej.

Pierwsza mikroskopijna rzecz jaka rzuca się w oczy to niepotrzebne `int32 dx = x1 - x0;` na początku, skoro później wewnątrz dużego if/else przesłaniasz tę zmienną czymś innym. Pewnie kompilator zjada to za Ciebie.

Druga rzecz to:

GR_fv_buf_x[_buff_id][y0] = x0;
GR_fv_buf_x_cell_id[_buff_id][y0] = GR_fv_proxy_cell_id;


Zauważ że robisz przypisanie `GR_fv_buf_x[_buff_id][y0] = x0;` z każdym przebiegiem pętli, a przecież czasem y0 nawet nie drgnie więc piszesz parę razy to samo w jedno miejsce. Może tak?

if (x0 == x1 && y0 == y1) {PRZYPIS; break; }

e2 = err << 1;

if (e2 >= dy)
{
	err += dy;
	x0++;
}

if (e2 <= dx)
{
	err += dx;
	PRZYPIS;
	y0++;
}


gdzie PRZYPIS to te dwie linie wyżej.

Trzecie. Można by spróbować pozbyć się `e2 = err << 1;`. Zauważ że dx/dy się nie ruszają w pętli, więc można by wyliczyć zawczasu `dx >> 1` oraz `dy >> 1` i do tego porównywać err. Z drugiej strony trzymanie tych wartości pod ręką pożre 2 rejestry i może być nieopłacalne, no i też przesunięcie w prawo jest stratną operacją, ale kto wie, może będzie to działać lepiej.

To co Ci mogę jeszcze podpowiedzieć to przepuścić to przez Compiler Explorer, zobaczyć jakie instrukcje asemblerowe są generowane, wkleić tu i może to nam coś podpowie. Może da radę ułożyć kod C żeby wychodził schludniejszy kod, albo da to komuś tutaj bazę na przepiszanie pod czystszy asembler.

EDYT: chyba możesz się pozbyć gigantycznego ifa jak zrobisz coś w stylu:

if(x1 < x0) {SWAP(x0, x1);}
dx = x1 - x0;


Jeszcze jedno. Mógłbyś zrobić wskaźnik na `GR_fv_buf_x[_buff_id]` i tego używać w pętli. Kompilator pewnie zrobił to za Ciebie, ale kto wie.

Ostatnia aktualizacja: 13.08.2022 10:44:20 przez teh_KaiN
2
[#3] Re: [ASM] Szybki algorytm rysowania linii w ASM

@teh_KaiN, post #2

Dzięki, potestuje..
[#4] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #1

Sprobuj moze tej implementacji, setup jest bardziej kosztowny ale wewnetrzna petla bedzie szybsza.

void GR_FV_Segment_To_Buffer(const int8 _buff_id, int32 x0, int32 y0, int32 x1, int32 y1)
{
	int32 dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
	int32 dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; 
	int32 err = (dx>dy ? dx : -dy)/2, e2;
 	
	for(;;)
	{
		GR_fv_buf_x[_buff_id][y0] = x0;
		GR_fv_buf_x_cell_id[_buff_id][y0] = GR_fv_proxy_cell_id;

		if (x0==x1 && y0==y1) break;
		e2 = err;
		if (e2 >-dx)
		{
			err -= dy; 
			x0 += sx;
		}
		if (e2 < dy)
		{
			err += dx;
			y0 += sy;
		}
	}
}
2
[#5] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #4

Hej.. to jest implementacja algorytmu Brasenhama z wiki, na której bazowałem. Tak ona jest szybką, natomiast kod który wkleiłem na początku jest trochę lepszy moim zdaniem, pozbyłem się abs() i zastąpiłem sx i st stałymi wiec jest to ciut szybsze.. ilość If w głównej pętli jest taka sama.
[#6] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #1

Skoro zapisujesz tylko dla [y] to po co robić wersję która jest dla poziomych linii (dx > dy) i zapisuje tą samą komórkę wielokrotnie? Zrób po prost wersję która zawsze inkrementuje Y i uaktualniaj tylko X (musisz zmienić nieco obliczenia).
3
[#7] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #1

A sprawdzałeś inne algorytmy, Wu i Efla ?
1
[#8] Re: [ASM] Szybki algorytm rysowania linii w ASM

@asman, post #7

Wu nie sprawdzałem,

EFLA jest ponoć szybszy od Wu i Brasenhama,
sprawdziłem wariant D i E z tych implementacji:
http://www.edepot.com/algorithm.html

E był wolniejszy od D, ale D miał praktycznie identyczną wydajność jak ten obecny
algorytm z którego korzystam, więc wolałem jego zostawić..
[#9] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #5

Nie, to nie jest ta sama implementacja, tylko nieco zoptymalizowana i 2 razy krotsza. Abs tu nie ma znaczenia, bo sie kompiluje do 3 instrukcji assemblera.
Z ciekawosci skompilowalem obie wersje (bez zapisu do tablic) gcc 2.95 z -O3 i kompilator calkiem dobrze sobie poradzil z optymalizacja- praktycznie nie ma miedzy nimi roznicy a kod jest na tyle dobrze wygenerowany, ze nia ma zbyt wiele miejsca na reczna optymalizacje. Tak wyglada glowna petla w pierwszym if.
.L7:
        move.l d1,d0
        add.l d0,d0
        cmp.l d0,d2
        jbgt .L8
        add.l d2,d1
        addq.l #1,a1
.L8:
        cmp.l d0,a0
        jblt .L4
        add.l a0,d1
        addq.l #1,d3
.L4:
        cmp.l a1,d4
        jbne .L7
        cmp.l d3,d5
        jbne .L7
        jbra .L11

Mysle, ze powinienies sie skupic na zapisach do tablicy - wygenerowany kod obu zapisow do tablic zajmuje wiecej cykli niz cala resztea petli!
.L7:
        move.l d1,d0
        add.l d0,d0
        cmp.l d0,d4
        jbgt .L8
        add.l d4,d1
        addq.l #1,a1
.L8:
        cmp.l d0,d3
        jblt .L4
        add.l d3,d1
        addq.l #1,d2
.L4:
-        move.l d5,a0
-        lea (a0,d5.l*4),a0
-        move.l a0,d0
-        lsl.l #3,d0
-        move.l d0,a4
-        lea (a4,d2.l*4),a0
-        move.l a1,(a0,a3.l)
-        move.l _GR_fv_proxy_cell_id,(a0,a2.l)
        cmp.l a1,d6
        jbne .L7
        cmp.l d2,d7
        jbne .L7

linie z minusem na poczatku to wyliczanie offsetu i zapis do tablic.
Sprobuj czegos takiego:

void	GR_FV_Segment_To_Buffer(const int8_t _buff_id, int32_t x0, int32_t y0, int32_t x1, int32_t y1)
{
	int* GR_fv_buf_x_ptr;
	int* GR_fv_buf_x_cell_id_ptr;

	int32_t e2, err;
	int32_t dx = x1 - x0;
	int32_t dy = y0 - y1;

	GR_fv_buf_x_ptr = &GR_fv_buf_x[_buff_id][0];
	GR_fv_buf_x_cell_id_ptr = &GR_fv_buf_x_cell_id[_buff_id][0];

	if (x0 < x1)
	{
		dx = x1 - x0;
		err = dx + dy;

		for (;;)
		{
			GR_fv_buf_x_ptr[y0] = x0;
			GR_fv_buf_x_cell_id_ptr[y0] = GR_fv_proxy_cell_id;
 
			if (x0 == x1 && y0 == y1) break;
			e2 = err << 1;
			if (e2 >= dy)
			{
				err += dy;
				x0++;
			}
			if (e2 <= dx)
			{
				err += dx;
				y0++;
			}
		}
	}
	else
	{
		dx = x0 - x1;
		err = dx + dy;
		for (;;)
		{
			GR_fv_buf_x_ptr[y0] = x0;
			GR_fv_buf_x_cell_id_ptr[y0] = GR_fv_proxy_cell_id;

			if (x0 == x1 && y0 == y1) break;
			e2 = err << 1;
			if (e2 >= dy)
			{
				err += dy;
				x0--;
			}
			if (e2 <= dx)
			{
				err += dx;
				y0++;
			}
		}
	}
}

Wygenerowany z tej wersji kod glownej petli wyglada tak:
.L7:
        move.l d1,d0
        add.l d0,d0
        cmp.l d0,d3
        jbgt .L8
        add.l d3,d1
        addq.l #1,a0
.L8:
        cmp.l d0,d2
        jblt .L4
        add.l d2,d1
        addq.l #4,a3
        addq.l #4,a2
        addq.l #1,a1
.L4:
        move.l a0,(a2)
        move.l _GR_fv_proxy_cell_id,(a3)
        cmp.l a0,d4
        jbne .L7
        cmp.l a1,d5
        jbne .L7

i powinien byc ze dwa razy szybszy od oryginalnego.
5
[#10] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #9

Hej, dzięki.. wygląda super. Przetestuję to potem OK
Dobra uwaga z tym buforem, zupełnie nie zauwazyłem

Ostatnia aktualizacja: 17.08.2022 19:43:03 przez mateusz_s
[#11] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #9

To powinno byc troche szybsze:

move.l _GR_fv_proxy_cell_id,d6 ; zamiast d6 moze byc dowolny wolny rejestr Dx lub Ax
.L7:
        move.l d1,d0
        add.l d0,d0
        cmp.l d0,d3
        jbgt .L8
        add.l d3,d1
        addq.l #1,a0
.L8:
        cmp.l d0,d2
        jblt .L4
        add.l d2,d1
        addq.l #4,a3
        addq.l #4,a2
        addq.l #1,a1
.L4:
        move.l a0,(a2)
;        move.l _GR_fv_proxy_cell_id,(a3)
        move.l d6, (a3)
        cmp.l a0,d4 
        jbne .L7
        cmp.l a1,d5
        jbne .L7
2
[#12] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #1

Int32 to jest konieczny w tym algorytmie?
Nie wiem na jaką to platformę ale operowanie na 16-bit może być szybsze. Jeśli to miałoby być uruchomione na 68000 to zdecydowanie będzie lepiej użyć rejestrów 16-bit

Poza tym nie widzę tutaj żadnego zabezpieczenia przed wyjściem poza bufor. Niby nie problem jak się punkty linii dobrze zawsze zdefiniuje ale zawsze.

Dobrą też praktyką jest handlowanie pionowych, i poziomych linii inaczej. Jeśli się ich dużo rysuje to można mocno zaoszczędzić na czasie. Poza tym nie dawałbym ifa w głównej pętli który za każdym razem sprawdza czy xy0 i xy1 są równe bo to marnowanie czasu procesora jak nie są równe. Lepiej to sprawdzić na samym początku.

Ustawianie piksela to najlepiej zrobić sobie inline makro w formie funkcji. Ja zawsze robiłem coś ala put_pixel(x, y, c). Lepiej to wygląda i łatwiej wtedy w razie potrzeby zmienić jedno makro np. ifdefem niż replace'ować w wielu miejscach kod, szczególnie jak on zajmuje więcej niż jedną linię.

Jest taka zasada w programowaniu: do not repeat yourself. Jak widzisz w kodzie duble to robisz od razu refactoring ok, racja
1
[#13] Re: [ASM] Szybki algorytm rysowania linii w ASM

@XoR, post #12

Hej,
Z tym int32 też prawda, zakresy są wczesniej wyclipowane do ekranu już więc faktycznie wystarczy int16

Linie poziome nie są rysowane tą funkcją kiedy jest wykryta linia pozioma wczesniej to bufora jest zapisana tylko wartość x0 i x1.

Pewnie można by też zrobić to samo dla pionowej..


Jak na razie dużo cennych uwag, dzięki Wszystkim postującym, ta funkcja będzie używana intensywnie
Więc każda optymalizacja się przyda.. jeszcze chwilowo jestem poza komputerem, dam znać czy coś się udało jeszcze urwać. OK
[#14] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #13

Dla int16 wychodzi cos takiego:
.L7:
        move.w d1,d0
        lsl.w #1,d0
        cmp.w d0,d4
        jbgt .L8
        add.w d4,d1
        addq.w #1,a1
.L8:
        cmp.w d0,d3
        jblt .L4
        add.w d3,d1
        addq.w #1,d2
.L4:
        move.w d2,a0
        move.w a1,(a3,a0.l*2)
        move.w _GR_fv_proxy_cell_id,(a2,a0.l*2)
        cmp.w a1,d5
        jbne .L7
        cmp.w d2,d6
        jbne .L7

Bedzie troche szybciej.
1
[#15] Re: [ASM] Szybki algorytm rysowania linii w ASM

@Don_Adan, post #11

Dobry pomysl, tylko pamietaj, ze to bylo wygenerowane z kodu w c. GR_fv_proxy_cell_id to jest jakas zmienna globalna, ale udalo mi sie te optymalizacje co zaproponowales tez uzyskac. Trzeba zadeklarowac zmienna lokalna w funkcji, ktora na poczatku jest inicjowana ta zmienna globalna i generuje sie wtedy cos takiego:
.L7:
        move.w d1,d0
        lsl.w #1,d0
        cmp.w d0,d4
        jbgt .L8
        add.w d4,d1
        addq.w #1,a1
.L8:
        cmp.w d0,d3
        jblt .L4
        add.w d3,d1
        addq.w #1,d2
.L4:
        move.w d2,a0
        move.w a1,(a3,a0.l*2)
        move.w d7,(a2,a0.l*2)
        cmp.w a1,d5
        jbne .L7
        cmp.w d2,d6
        jbne .L7

Jak na c, to jest swietny kod. Nie widze tu za wiele miejsca na jakies dodatkowe optymalizacje.
2
[#16] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #15

Ja zamiast
lsl.w #1,d0
dalbym
add.w d0,d0
2
[#17] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #15

1. Pozbywamy się mnożenia indeksu * 2 w tyvh liniach:
move.w a1,(a3,a0.l*2)
move.w d7,(a2,a0.l*2)

Nie wiem jak kod wygląda wcześniej ale jedyną zmianę d2 widzę tu:
addq.w #1,d2
zamieniamy na:
addq.w #2,d2
i możemy zmienić na:
move.w a1,(a3,a0.l)
move.w d7,(a2,a0.l)

2. Przed pętlą obliczamy różnicę adresu a2 i a3
sub.l a3,a2

3. Zmieniamy tryby adresowania z indeksowego na bezpośredni

.L4:
move.l a3,a0
add.w d2, a0
move.w a1,(a0)
add.l a2, a0
move.w d7,(a0)

cmp.w a1,d5
jbne .L7
cmp.w d2,d6
jbne .L7


Jeżeli d2 jest zmieniane tylko w tej linii:
addq.w #2,d2
to można przyspieszyć kod dodając przed pętlą a3 do d2 oraz a3 do d6, rozszerzając oba rejestry do długiego słowa
i wtedy mamy:

.L4:
move.l d2, a0
move.w a1,(a0)
add.l a2, a0
move.w d7,(a0)
cmp.w a1,d5
jbne .L7
cmp.l d2,d6
jbne .L7

na 020 zysk 10 cykli.
3
[#18] Re: [ASM] Szybki algorytm rysowania linii w ASM

@Kefir_Union, post #17

Nie wiem jak kod wygląda wcześniej ale jedyną zmianę d2 widzę tu:
addq.w #1,d2
zamieniamy na:
addq.w #2,d2
i możemy zmienić na:
move.w a1,(a3,a0.l)
move.w d7,(a2,a0.l)

Zapomniałem o pomnożeniu przez dwa d6 przed pętlą.
3
[#19] Re: [ASM] Szybki algorytm rysowania linii w ASM

@Kefir_Union, post #17

1.
d2 musi byc zwiekszane o 1, to jest ten fragment kodu w c: y++, takze ta optymalizacja odpada. Poza tym, z tego co pamietam to skalowanie indeksu jest za darmo wiec nie byloby zadnego zysku.
3.
Tu na pierwszej zmianie w teorii (bazujac tylko na ilosci cykli w cache) mozna by zyskac 2 cykle, druga odpada ze wzgledu na wymog z p. 1.

Jednak ze wzgledu na overlapping tego zysku nie bedzie np. w tej sekwencji

.L4
move.w d2,a0
move.w a1,(a3,a0.l*2)
move.w d7,(a2,a0.l*2)

pierwsza instrukcja wykona sie w 2 cykle, druga w 7, a trzecia w 4 = 13
Natomiast w twojej propozycji:

.L4
move.l a3,a0
add.w d2, a0
move.w a1,(a0)
add.l a2, a0
move.w d7,(a0)

pierwsza instrukcja wykona sie w 2 cykle, druga w 2, trzecia w 6, czwarta w 0 i piata w 6, w sumie 16
1
[#20] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #19

Poza tym, z tego co pamietam to skalowanie indeksu jest za darmo wiec nie byloby zadnego zysku.

Mnożenie indeksu nic nie kosztuje ale trzeba je wyrzucić żeby pozbyć się trybu adresowania z indeksem.


move.l d2, a0
move.w a1,(a0)
add.l a2, a0
move.w d7,(a0)

Pierwsza 2 cykle
Druga 4 cykle
Trzecia 2 cykle
Czwarta 4
Razem 12 cykli.

W manualu od 020 i 030 w opisie jak działa overlapping nie ma nic na temat ograniczenia ze względu na wykorzystanie przez występujące po sobie instrukcje tych samych rejestrów. W takim przypadku obie instrukcje zapisu zajmą po 3 cykle, czyli całość 10 cykli.
1
[#21] Re: [ASM] Szybki algorytm rysowania linii w ASM

@Kefir_Union, post #20

W takim przypadku obie instrukcje zapisu zajmą po 3 cykle

Też źle napisałem. W manualu 030 jest podział na head/tail i mamy:

add Rn, Dn - H2 T0
move.l Rn,(An) - H0, T1

Czyli:
Pierwsza 2 cykle
Druga 4 cykle
Trzecia 1 cykl (wchodzi na ogon poprzedniej instrukcji)
Czwarta 4 cykle
Razem 11 cykli.
[#22] Re: [ASM] Szybki algorytm rysowania linii w ASM

@docent, post #19

move.w d2,a0
move.w a1,(a3,a0.l*2)
move.w d7,(a2,a0.l*2)


move.w d2,a0 - H2 T0
move.w a1,(a3,a0.l*2) - H4 T0
move.w d7,(a2,a0.l*2) - H4 T0

Czas wykonywania:
2 cykle
7 cykli
7 cykli
Razem 16 cykli.

Nie ma overlappingu między instrukcjami zapisu ponieważ on zachodzi tylko gdy wartości Head pierwszej instrukcji oraz Tail kolejnej instrukcji, są większe od zera. W naszym przypadku min(H, T) wynosi zero.

Ostatnia aktualizacja: 20.08.2022 09:22:24 przez Kefir_Union
[#23] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #1

Hej,
dzięki Wszystkim za pomysły i porady - udało się urwać parę fps.
Można śmiało powiedzieć że poniższa wersja wykonuje się znacznie szybciej.

Oczywiście najlepiej by było porównać te zmiany w jakimś uszytym teście z dokładnym timerem,
ale nie chciało mi się tego ustawiać, wiec wrzuciłem od razu do swojego Projektu.

Na V1200 wg referencyjnej nie uproszczonej sceny wyszło mi ok 4 fps przyrostu, wiec spoko.

Poszczególne kroki testowałem z kolei na emulatorze, ale w bardziej uproszczonej scenie
żeby nie zamulać nie potrzebnymi rzeczami, tu był wzrost od ok. 145 do ok. 161 fps.

Finalnie zastosowałem te zmiany:
01. zamiana int32 na int16, tutaj nie zauważyłem jakiejś różnicy, ale int16 w zupełności wystarczy
02. Pobranie wskaźników na samych początku, zamiast za każdym razem w pętli, tutaj znaczny przyrost ok 4-5 fps.
03. Zapis do bufora tylko przy zmianie Y lub wyjściu - tutaj też ok. 4-5 fps - tylko tutaj pojawia się czasami mały babol i nieraz brakuje jednego pixelu w rogu,
ale szkoda bylo dobrego przyrostu, moze nie bedzie tego widać, jak bedzie no to trzeba bedzie zabrać..
04. Pozbycie się testu (x0==x1) w ogóle, ok. 3-4 fps.

Nie korzystałem jednak z porad które dotyczyły bezpośrednio asm, bo nie wiem czy bym je poprawnie wdrożył.

Poniżej kod obecnej optymalnej wersji:

Tu w Compiler Explorer, gcc 6-5-0-b
http://franke.ms/cex/z/dY71vq

void	GR_FV_Segment_To_Buffer(const int8 _buff_id, int16 x0, int16 y0, const int16 x1, const int16 y1)
{
	int16* fv_buf_x__READY = &GR_fv_buf_x[_buff_id][0];
	int16* fv_buf_x_cell_id__READY = &GR_fv_buf_x_cell_id[_buff_id][0];

	const int16 dy = y0 - y1;
	int16 e2;

	if (x0 < x1)
	{
		const int16 dx = x1 - x0;
		int16 err = dx + dy;

		for (;;)
		{
			e2 = err << 1;

			if (e2 >= dy)
			{
				err += dy;
				x0++;
			}

			if (e2 <= dx)
			{
				fv_buf_x__READY[y0] = x0;
				fv_buf_x_cell_id__READY[y0] = GR_fv_proxy_cell_id;

				err += dx;
				y0++;

				if (y0 == y1)
				{
					fv_buf_x__READY[y0] = x0;
					fv_buf_x_cell_id__READY[y0] = GR_fv_proxy_cell_id;
					break;
				}
			}
		}
	}
	else
	{
		const int16 dx = x0 - x1;
		int16 err = dx + dy;

		for (;;)
		{
			e2 = err << 1;

			if (e2 >= dy)
			{
				err += dy;
				x0--;
			}

			if (e2 <= dx)
			{
				fv_buf_x__READY[y0] = x0;
				fv_buf_x_cell_id__READY[y0] = GR_fv_proxy_cell_id;

				err += dx;
				y0++;

				if (y0 == y1)
				{
					fv_buf_x__READY[y0] = x0;
					fv_buf_x_cell_id__READY[y0] = GR_fv_proxy_cell_id;
					break;
				}
			}
		}
	}
}


Ostatnia aktualizacja: 20.08.2022 23:26:42 przez mateusz_s
1
[#24] Re: [ASM] Szybki algorytm rysowania linii w ASM

@mateusz_s, post #23

Coś dużo FPS na emulatorze względem sprzętu, uważaj z tym. Używaj trybu cycle exact - bo inaczej JIT Cię może robić w konia i będziesz optymalizował pod niego, a okaże się że na żywym sprzęcie jest gorzej.
1
[#25] Re: [ASM] Szybki algorytm rysowania linii w ASM

@teh_KaiN, post #24

Nie używam JIT na emulatorze. Bylo szybko bo zostawiłem tylko rysowanie kolorem zeby bardziej widzieć zmiany w tym algorytmie.

Pod V1200 mam zawsze ok. 2x szybciej niż na winuae
Na tych ustawieniach z których korzystam.
[#26] Re: [ASM] Szybki algorytm rysowania linii w ASM

@Kefir_Union, post #20

Napisales cos takiego:
1. Pozbywamy się mnożenia indeksu * 2 w tyvh liniach:
move.w a1,(a3,a0.l*2)
move.w d7,(a2,a0.l*2)
...
i możemy zmienić na:
move.w a1,(a3,a0.l)
move.w d7,(a2,a0.l)
Ja to zrozumialem jako propozycje optymalizacji, a to nic nie przyspieszy :)

Jak juz pisalem wczesniej, d2 jest biezaca wspolrzedna y, zwiekszana o 1 wiec nie mozesz wykorzystac tej optymalizacji z d2 z redukcja do 4 instrukcji. Do policzenia wzialem wiec 5 instrukcji, ktore zaproponowales wczesniej.

Nigdzie nie napisalem, ze overlapping ma ograniczenia, wynikajace z występowania po sobie instrukcji z tymi samymi rejestrami. Ovelapping wynika ze wspolbieznosci pracy bus kontrolera i sekwencera instrukcji. Przy zalozeniu, ze kod jest 32bit aligned i znajduje sie w cache procesora, oryginalny kod na 68030 wykonuje sie tak:
cykle:			- - - - | - - - - | - - - - | - - - - | - - - - 	head	tail	cc
move.w d2,a0		* *							2	0	2
move.w a1,(a3,a0.l*2)	    * *	  * * * *					4	0	6
move.w d7,(a2,a0.l*2)	                    * * * *   * *			4	0	6
bus:
r
w			              + +             + + 
seq:
exec1			+ +							
calc2 dest		    + +   + +
exec2				      + + 
calc3 dest			            + + + +
exec3 					              + +


2+
6-min(4,0)+
6-min(4,0)
= 14

cykle:			- - - - | - - - - | - - - - | - - - - | - - - - 	head 	tail	cc
move.l a3,a0            * *							2	0	2
add.w d2, a0                * *   * *						4	0	4
move.w a1,(a0)                        * *   *  					0	1	3
add.l a2, a0                                * *					2	0	2
move.w d7,(a0)                                  * *   *  			0	1	3
bus
r
w			                +   +     +   + 
seq:
exec1			+ +
exec2			    + +   + +
calc dest+exec3			      + + 
exec4				            + +  
calc dest+exec5 			        + +

2+
4-min(0, 0)+
3-min(0, 0)+
2-min(2, 1)+
3-min(0, 0)
= 13
1
[#27] Re: [ASM] Szybki algorytm rysowania linii w ASM

@Kefir_Union, post #22

move.w a1,(a3,a0.l*2) ma 7 cykli na 68020, a na 68030, wg manuala, na ktorym bazujesz informacje o timingach, ma 6 cykli. Czyli czas wykonywania na 68030 wynosi 14 cykli a nie 16. Na 68020 czas wykonywania tej sekwencji wynosi 15 cykli, poniewaz na 68020 ta instrukcja ma tail nie 0 lecz 1.

Ostatnia aktualizacja: 21.08.2022 13:01:59 przez docent
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