kategorie: ANSI C, Asembler
[#1] [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)
Czołem,
To moja najbardziej wewnętrzna pętla (w postaci funkcji),
która renderuje jeden pojedyńczy poziomy pasek, z użyciem textur, lightmapy i distance shading.
Jest ona uruchamiana dla każdej poziomej linii tworzącej dany polygon.

Nie wiem czy można to jakoś jeszcze zoptymalizować, może macie jakieś pomysły, jakieś sztuczki magiczki w asm itp :)

Wrzucam kod w Compiler Explorer:
http://franke.ms/cex/z/PT9r1E

i kod funkcji tutaj:

void rend_horizontal_stripe(int32 draw_length,
                                        int32 floor_x__fp, int32 floor_y__fp, int32 floor_step_x__fp, int32 floor_step_y__fp, 
                                        u_int8* lightmap__READY, int8* texture_256__READY,
                                         const u_int8 tex_size, u_int32* output_buffer_32__READY, 
                                        int32* texture_intensity, int32* distance_shading_flats__LUT__READY)
{
	
	while (draw_length >= 0)
	{
		// 01. Lets find current x,y coords in lightmap bitmap. The lightmap bitmap is 32 x 32 px.	
			
			// BEFORE OPTIMALIZATION
			// int32 lm_tx = (int32)((floor_x__fp << 5) >> 18)  & (IO_LIGHTMAP_SIZE - 1);
			// int32 lm_ty = (int32)((floor_y__fp << 5) >> 18)  & (IO_LIGHTMAP_SIZE - 1);
			
			// AFTER OPTIMALIZATION: 
			int32 lm_x = (int32)((floor_x__fp) >> 13) & (32 - 1);
			int32 lm_y = (int32)((floor_y__fp) >> 13) & (32 - 1);

		// 02. Now we can get intensity valie from ligtmap - its 8-bit value from 0 to 127.
			int32 lm_intensity_value = lightmap__READY[lm_x + (lm_y << 5)];


		// 03. Lets find current x,y coords in texture bitmap.		
		
			// BEFORE OPTIMALIZATION
			// int32 tx = (int32)((floor_x__fp << 8) >> 18) & (255);
			// int32 ty = (int32)((floor_y__fp << 8) >> 18) & (255);

			// AFTER OPTIMALIZATION: 
			int32 tx = (int32)((floor_x__fp) >> 10) & (tex_size);
			int32 ty = (int32)((floor_y__fp) >> 10) & (tex_size);

		// 04. Now we can get index to color table from texture bitmap.

			u_int8 texture_pixel_index = texture_256__READY[tx + (ty << 8)];


		// 05. We would like also to use distance shading.
		//	   Lets take our intensity value from lighmap (from 02) and use it in precalculated array "distance_shading_flats__LUT__READY" 
		//	   to get lightmap intensity value affected by distance.
		//     With that final lightmap intensity value we can move pointer to correct color table for that texture
		u_int32* texture_intensity_lm = texture_intensity + distance_shading_flats__LUT__READY[lm_intensity_value];


		// 06. Use texture index (from 04) to get RGBA pixel from correct color table. Put the pixel in output_buffer.

		*output_buffer_32__READY = texture_intensity_lm[texture_pixel_index];
		output_buffer_32__READY++;

		floor_x__fp += floor_step_x__fp;
		floor_y__fp += floor_step_y__fp;

		draw_length--;
	}

}


Ostatnia aktualizacja: 23.08.2022 15:19:46 przez mateusz_s

Ostatnia aktualizacja: 23.08.2022 15:20:26 przez mateusz_s
[#2] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@mateusz_s, post #1

Na mojej przegladarce (starszy Chrome) jest tam pusto. Mozesz tutaj wkleic wersje ASM.
[#3] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@Don_Adan, post #2

z flagami:
-O3 -m68060 -mtune=68060 -mhard-float -fomit-frame-pointer -funroll-all-loops
_rend:
        movem.l a6/a5/a4/a3/a2/d7/d6/d5/d4/d3/d2,-(sp)
        lea (48,sp),a1
        move.l (a1)+,d4
        move.l (a1)+,d0
        move.l (a1)+,d1
        move.l (a1)+,(60,sp)
        move.l (a1)+,d6
        move.l (a1)+,a2
        move.l (a1)+,d7
        move.l (a1)+,d3
        move.l (a1)+,a0
        move.l (a1)+,a3
        move.l (a1),a4
        and.l #255,d3
        tst.l d4
        jlt .L1
        moveq #1,d2
        and.l d4,d2
        move.l d2,a1
        move.l d1,d2
        lsr.l #8,d2
        move.l #992,d5
        and.l d2,d5
        bfextu d0{#14:#5},d2
        or.l d2,d5
        move.b (a2,d5.l),d5
        and.l #255,d5
        move.l d1,d2
        asr.l #8,d2
        asr.l #2,d2
        and.l d3,d2
        lsl.l #8,d2
        move.l d2,a5
        move.l d0,d2
        asr.l #8,d2
        asr.l #2,d2
        add.l d7,a5
        and.l d3,d2
        move.b (a5,d2.l),d2
        add.l (a4,d5.l*4),d2
        move.l (a3,d2.l*4),(a0)+
        add.l (60,sp),d0
        move.l d4,a5
        add.l d6,d1
        subq.l #1,a5
        cmp.w #-1,a5
        jeq .L1
        move.l a1,d2
        jeq .L9
        move.l d1,d2
        lsr.l #8,d2
        and.l #992,d2
        bfextu d0{#14:#5},d5
        or.l d5,d2
        move.b (a2,d2.l),d2
        and.l #255,d2
        move.l d2,a6
        move.l d1,d2
        asr.l #8,d2
        asr.l #2,d2
        and.l d3,d2
        lsl.l #8,d2
        move.l d2,a1
        move.l d0,d2
        asr.l #8,d2
        asr.l #2,d2
        add.l d7,a1
        and.l d3,d2
        move.b (a1,d2.l),d2
        add.l (a4,a6.l*4),d2
        move.l (a3,d2.l*4),(a0)+
        add.l (60,sp),d0
        add.l d6,d1
        move.l a5,d2
        jeq .L1
.L9:
        lsr.l #1,d4
        subq.l #1,d4
.L5:
        move.l d1,d2
        lsr.l #8,d2
        and.l #992,d2
        bfextu d0{#14:#5},d5
        or.l d5,d2
        move.b (a2,d2.l),d2
        and.l #255,d2
        move.l d2,a5
        move.l d1,d2
        asr.l #8,d2
        asr.l #2,d2
        and.l d3,d2
        lsl.l #8,d2
        move.l d0,d5
        asr.l #8,d5
        asr.l #2,d5
        move.l d7,a1
        and.l d3,d5
        add.l d2,a1
        clr.l d2
        move.b (a1,d5.l),d2
        add.l (a4,a5.l*4),d2
        move.l (a3,d2.l*4),(a0)+
        add.l (60,sp),d0
        add.l d6,d1
        move.l d1,d2
        lsr.l #8,d2
        and.l #992,d2
        bfextu d0{#14:#5},d5
        or.l d5,d2
        move.b (a2,d2.l),d2
        and.l #255,d2
        move.l d2,a5
        move.l d1,d2
        asr.l #8,d2
        asr.l #2,d2
        and.l d3,d2
        lsl.l #8,d2
        move.l d0,d5
        asr.l #8,d5
        asr.l #2,d5
        move.l d7,a1
        and.l d3,d5
        add.l d2,a1
        clr.l d2
        move.b (a1,d5.l),d2
        add.l (a4,a5.l*4),d2
        move.l (a3,d2.l*4),(a0)+
        add.l (60,sp),d0
        add.l d6,d1
        subq.l #1,d4
        jcc .L5
.L1:
        movem.l (sp)+,d2/d3/d4/d5/d6/d7/a2/a3/a4/a5/a6
        rts
[#4] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@mateusz_s, post #3

jedyne co mi się jeszcze tu nasuwa to próba pozbycia się tych wraperów & 31 i & 255
ale nie wiem czy sie da, bede probowal potem..
[#5] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@mateusz_s, post #4

Tak na szybko to to:
or.l d5,d2
        move.b (a2,d2.l),d2
        and.l #255,d2
        move.l d2,a5
        move.l d1,d2
        asr.l #8,d2
        asr.l #2,d2
        and.l d3,d2
        lsl.l #8,d2
        move.l d0,d5


mozna by zamienic na cos takiego:

or.l d2,d5
        moveq #0,d2
        move.b (a2,d5.l),d2
;        and.l #255,d2
        move.l d2,a5
        move.l d1,d2
        asr.l #8,d2
        asr.l #2,d2
; nie pamietam juz czy
;  moveq #10,d5
; asr.l d5,d2
; jest szybsze niz 2x asr.l, czy taka sama szybkosc ma
        and.l d3,d2
        lsl.l #8,d2
        move.l d0,d5


Czyli 4 bajty mniej w petli, na pewno cala procedure da sie przyspieszyc bardziej przez lepsze uzycie rejestrow, ale to i tak jest calkiem niezly kod jak na kompilator, bo uzywa wszystkich rejestrow.

Ostatnia aktualizacja: 24.08.2022 01:34:15 przez Don_Adan
1
[#6] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@mateusz_s, post #1

W jakim formacie fixed point sa parametry wejsciowe do funkcji?
1
[#7] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@docent, post #6

chyba 18:14

zamieniam na fixed pointa w ten sposób:
int32 floor_step_x__fp = (int32)(floor_step_x * 262144.0f);


czyli mnożę razy 2^18
[#8] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@Don_Adan, post #5

Wklejam jeszcze wiekszy fragment kodu, ktory wywoluje wspomnianą funkcję:

w sumie to chyba nie da sie juz w tym kodzie wiecej zrobic, tak mi sie wydaje..

ewentualnie to jakies włąśnie takie poprawki w ASM


// -- Step 07. --
			// After points are projected, segments clipped and rasterized into x0 and x1 buffers,
			// the current floor and ceil polygons can be rendered.

			// Render the FLOOR if the final floor poly has more than 2 segments.

			if (floor_poly_size > 2)
			{

				int8* texture_256__READY = LV_map[pvc_cell_id].flat_texture__PTR[0];

				int32* texture_intensity = LV_map[pvc_cell_id].flat_texture_intensity__PTR[0];
				u_int8* lightmap__READY = LV_map[pvc_cell_id].flat_lightmap__PTR[0];

			
				for (int32 ray_y = floor_y_min; ray_y <= floor_y_max; ray_y++)
				{
				
							float32 ray_y_pos = ray_y - GR_horizont;
							float32 straight_distance_to_point = fabsf(pp_z__floor / ray_y_pos);

							// Calculate distance intensity value based on wall distance.
							 int32 distance_intensity = (int32)(straight_distance_to_point * GR_DISTANCE_INTENSITY_SCALE);
							//int32 distance_intensity = (int32)(straight_distance_to_point *4/** GR_DISTANCE_INTENSITY_SCALE*/);
							distance_intensity = MA_MIN_2(distance_intensity, (GR_DISTANCE_INTENSITY_LENGTH - 1));

							//	u_int32* texture_intensity__READY = texture_intensity + 127 * 128;

								// Move pointer to correct distance in distance shading LUT.
							int32* distance_shading_flats__LUT__READY = GR_distance_shading_flats__LUT[distance_intensity];

							float32 floor_step_x = (straight_distance_to_point * rdx1__sub__rdx0__div__width) ;
							float32 floor_step_y = (straight_distance_to_point * rdy1__sub__rdy0__div__width) ;

							float32 floor_x = (PL_player.x + (straight_distance_to_point * ray_dir_x0)) + floor_step_x * GR_fv_buf_x[0][ray_y];
							float32 floor_y = (PL_player.y + (straight_distance_to_point * ray_dir_y0)) + floor_step_y * GR_fv_buf_x[0][ray_y];

							floor_x -= (int8)floor_x;
							floor_y -= (int8)floor_y;

							int32 floor_step_x__fp = (int32)(floor_step_x * 262144.0f);
							int32 floor_step_y__fp = (int32)(floor_step_y * 262144.0f);

							int32 floor_x__fp = (int32)(floor_x * 262144.0f);
							int32 floor_y__fp = (int32)(floor_y * 262144.0f);

							int32 draw_start_in_buffer = GR_fv_buf_x[0][ray_y] + ray_y * GR_render_width;
							u_int32* output_buffer_32__READY = IO_prefs.output_buffer_32 + draw_start_in_buffer;
							

							int32 draw_length = GR_fv_buf_x[1][ray_y] - GR_fv_buf_x[0][ray_y];


							GR_Render_Flats_Horizontal_Stripe(  draw_length, 255, 8, 10, floor_x__fp, floor_y__fp, floor_step_x__fp, floor_step_y__fp,
																lightmap__READY, texture_256__READY, texture_intensity, distance_shading_flats__LUT__READY, output_buffer_32__READY);
				}
			}


Ostatnia aktualizacja: 24.08.2022 03:21:34 przez mateusz_s

Ostatnia aktualizacja: 24.08.2022 03:22:58 przez mateusz_s
[#9] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@mateusz_s, post #8

Jesli da sie przerobic tabele (?) spod rejestru A2, z bajtow na dlugie slowa to zamiast tego:

move.b (a2,d2.l),d2
and.l #255,d2
move.l d2,a5

mozna by uzyc tylko jednej instrukcji:

move.l (a2,d2.l*4),a5

Nie wiem jaka jest maksymalna wartosc dla rejestru d4 (petli), bo zwykle na wszystkich procesorach (oprocz chyba 68080) dbra/dbf jest szybsze niz subq.l + bxx. Ale dbra/dbf jest dla maks 16 bitowej wartosci.
1
[#10] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@mateusz_s, post #7

Jesli dokladnosc bedzie wystarczajaca to sprobuj przejsc na 16:16. W takim formacie odczyt czesci calkowitej to najczesciej bedzie 1 instrukcja (swap) zamiast dwoch asr.
2
[#11] Re: [C, ASM] Pomoc przy optymalizacji tego kodu.. (texturowanie poziomego paska)

@docent, post #10

hej,
ciekawy pomysł, sprawdze to..
ale wydaje mi się że 16:16 to bedzie za mało
bo step-y mogą mieć bardzo małe wartości rzędu 0.001 nieraz 0.0001
daltego musialem pomnozyć przez dużą wartość..
w przeciwnym wypadku textury sie rozjeżdzały
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