Machine Code: Moving from Attribute scrolling to pixel scrolling

The place for codemasters or beginners to talk about programming any language for the Spectrum.
User avatar
Joefish
Rick Dangerous
Posts: 2059
Joined: Tue Nov 14, 2017 10:26 am

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by Joefish »

ketmar wrote: Fri Mar 22, 2024 8:38 am by the way, you cannot copy the whole screen in one frame, not even using stack tricks. there is simply not enough tstates. you may be able to build it from several tiles, but copying fullscreen backbuffer and keeping 50 FPS is physically impossible.
This is true. This is the first time I got it working (with parallax background too!), although 128K only. It does waste a bit of time as there's no need to redraw the attributes every frame in a pixel scroll. But then technically it could scroll at any speed, or jump to any place on the map instantly.

The matter is that there isn't enough time to both read and write a full screen of data in one frame. But by loading a minimal set of tile data into registers, you're cutting back enormously on the amount of data you have to read, so that leaves you with enough time to write an entire screen of data. And that doesn't take much longer than wiping the screen entirely, as you'd still have to write a lot of zeroes just to do that.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by ketmar »

by the way, it is possible to do this (copy the whole screen in one frame) on Pentagon. it has slightly more tstates per frame, and no wait states. but you have to load values directly into registers in blit routine, so drawing to such backbuffer is a PITA, and will kill the performance anyway. but you can do fullscreen vertical scroll with static image at 50 FPS (albeit the image should be monochrome, afair). not that it has any practical sense outside of demos, tho.
User avatar
ParadigmShifter
Manic Miner
Posts: 670
Joined: Sat Sep 09, 2023 4:55 am

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by ParadigmShifter »

This

https://github.com/Liniya/intenseoffici ... -test1.sna

was linked to in my WoS thread which looks like 50FPS and on the 48K but I didn't try and disassemble it.

I think it's way faster to redraw the whole screen than to attempt to rotate what is already on the screen anyway. (For horizontal scrolling anyway). If there's a large amount of blank space copying parts of the screen might start to win though.

In my columns game I am actually copying the screen contents when I move a column down 8 pixels (it only scrolls 8 pixels at a time) which I haven't timed much when it is very busy scrolling a lot of columns at once, it runs ok with no noticeable flicker though (and scrolling what is on screen means I don't have to check the collision map to work out what to draw where).
User avatar
ParadigmShifter
Manic Miner
Posts: 670
Joined: Sat Sep 09, 2023 4:55 am

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by ParadigmShifter »

So I assume the Hewson article was talking about scrolling in Uridium which sounds like it uses a back buffer. Screen area seems to be 16 rows x 28 or 30 columns (probably uses the full 32 columns for clipping purposes though). It also sounds like they are doing a ton of copying (keep the background layer in a separate buffer, copy it to the off screen buffer, then draw the sprites?) which sounds like a big waste of memory. Uridium is smooth though I did not attempt to guess the frame rate (I am guessing not 25fps though).

Joffa's stuff seems a lot more impressive than that. And GNG was good for what it was doing (the graphics were very limited in that they had to be 4 cells wide if they tiled though), and that was unrolled up the wazoo. My spectrum broke soon after so I didn't see if the GNG Guy (was Keith Burkhill I think) went on to improve his scrolling engine later on.
Ralf
Rick Dangerous
Posts: 2289
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by Ralf »

If we talk about scrolling, then a good game to discuss is Stormlord:
https://spectrumcomputing.co.uk/entry/4 ... /Stormlord

It allows much more variety in background tiles than let's say Cobra. Cobra is actually very limited and allows background built only with a few tiles.

Here is my old post about Stormlord:
viewtopic.php?p=1937#p1937
User avatar
Joefish
Rick Dangerous
Posts: 2059
Joined: Tue Nov 14, 2017 10:26 am

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by Joefish »

Uridium runs at 25fps, so there's no time for multiple screen copies. There are plenty of tricks it could be using, all of them very complicated. The dreadnought designs aren't exact copies of the C64 ones either, so it seems there are limitations to what it can render. And even at it's slowest it's a 2-pixel scroll, not 1.
User avatar
ParadigmShifter
Manic Miner
Posts: 670
Joined: Sat Sep 09, 2023 4:55 am

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by ParadigmShifter »

Anyway it is complicated to answer the OPs question ;) And you need to do a lot of quite complicated stuff to get it to run fast (use the stack to copy, preshift your graphics, lots of unrolling).

Joefish's 128K scroller linked to earlier has the source available and I would have a look at that (that was when I gave up on my own scroller since I saw Joefish had basically already done what I was trying to do anyway, and there was some gnarly bug trying to make my tiles 48x16 instead of 16x16 which I never got around to fixing). His code is better than mine :) (although it was my first attempt at scrolling).

I also borrowed part of my line copy routine from another poster on WoS which uses each row of the preshifted graphics offset by 256 bytes for each row to avoid having to add anything to HL when moving down a row, you can just INC H instead, which was a good idea. I can't remember if Joefish did that in his code or not. That made it harder to debug though I seem to remember lol ;) You don't end up wasting space you can put other graphics offset by the width (so my first preshifted tile is at someaddress, next line down preshifted to someaddress+256, etc. and the next tile is at someaddress + 16, etc.)

Or you can use an offscreen buffer which is easy but I expect you won't be able to run faster than 16.7 fps then (which isn't that bad tbh, especially if it is your first attempt at a scroller).

EDIT: Ghosts N' Goblins does not preshift it just rotates the tiles by the scroll delta amount each frame IIRC. The tiles repeat every 4 cells though I think which is quite restricting (but you can draw them at any width on the screen via a load of unrolled code - one routine to draw 30 cell width repeated tile, another to draw 29 cell width, and so on.
User avatar
Hedge1970
Manic Miner
Posts: 388
Joined: Mon Feb 18, 2019 2:41 pm

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by Hedge1970 »

Thanks for all the great input, much of it does not make any sense at the moment but I will endeavour to learn more. What I take away is I will leave it as is for now but I must implement some code - and potentially optimise my code - to write to screen following the Rasta scan.
C.Born
Manic Miner
Posts: 230
Joined: Sat Dec 09, 2017 4:09 pm

Re: Machine Code: Moving from Attribute scrolling to pixel scrolling

Post by C.Born »

ParadigmShifter wrote: Thu Mar 21, 2024 3:13 pm Forgot to post the link where I got the info about the raster from

https://worldofspectrum.org/faq/referen ... erence.htm
i have my own notations, hope it helps a little
the IM2 is not needed offcourse

Code: Select all

; http://www.worldofspectrum.net/faq/reference/128kreference.htm
;         model            -128k     -timings in T-state
;       T-state             228       per raster-scanline
;      Scanline             311       per frame
; screen build in blocks with timing:
; hiddenlines  00000-03419t  000-014  15= 3420
; border-uppr  03420-14364t  015-063  48=10944
; screen       14365-58140t  064-255 192=43776
; border-under 58141-70907t  256-310  56=12768
;              ---+-----     ---+-----
;        total        311=70908

;         borderline  =  38 * 228 = 8664
;         borderline  =  39 * 228 = 8892
;         borderline  =  40 * 228 = 9120
;         borderline  =  41 * 228 = 9348
;         borderline  =  42 * 228 = 9576
;   borderline  =  43 * 228 = 9804
;     1st screenline  =  63 * 228 =14364
;first pix @16384        14364-1 t (zero-offset)

;A 128k-video screen line (228t) is timed as follows:
; 128 T (  0-127) states of screen,       (left to right )      CONtended
;  24 T (128-151) states of right border, (right to left !!!) UNcontended
;  48 T (152-199) states of horizontal retrace and            UNcontended
;  28 T (200-227) states of left border.  (4t extra on 224t ) UNcontended

; per scan line 
;           0t        128t
;       ----|+++ > +++|----151t
;                            /
;   199t    -    <    -    152t
;     /
;   200t    228t      356t
;       ----|+++ > +++|----379t
;                            /
;   427t    -    <    -    380t
;     /
;   428t    456t
;       ----|---->----|----

;      screen time (  0-127) = 128 tstate, 
;right border time (128-151) =  24
;      retracetime (152-199) =  48
; left border time (200-227) =  28 =128 24+48+28 = 228
;      screen time (228-355) = 128
;right border time (356-379) =  24
;     retrace time (380-427) =  48
; left border time (428-455) =  28 total 456 tstate

;https://www.worldofspectrum.net/faq/reference/z80reference.htm#Interrupts
;In IM 2, it takes 19 cycles to get to the interrupt routine:
;    M1: 7 T states: acknowledge interrupt and decrement SP
;    M2: 3 T states: write high byte and decrement SP
;    M3: 3 T states: write low byte
;    M4: 3 T states: read low byte from the interrupt vector
;    M5: 3 T states: read high byte and jump to interrupt routine

; next t=+1  ULA interrupt does not wait for an instruction, so the instruction can be contended HALFWAY
;      ut       tstate  average division
;        ...... 
;    48k/128k+2 Cycle  +2A/+3
; 6 14335 7       x/8=y.875 j.needle
;@16384 5 14336 6 x/8=y.00  64x224 null start !!
; 4 14337 5 x/8=y.125
; 3 14338 4 x/8=y.25
;      *2 14339 3       x/8=y.375
;      *1 14340 2 x/8=y.50
;      *0 14341 1 x/8=y.625  <<<
;      *0 14342 0 x/8=y.75   <<<
; 6 14343 7       x/8=y.875
; 5 14344 6 x/8=y.00
; 4 14345 5 x/8=y.125
; 3 14346 4 x/8=y.25
; 2 14347 3       x/8=y.375
; 1 14348 2 x/8=y.50
; 0 14349 1 x/8=y.625
; 0 14350 0 x/8=y.75
; 6 14351 7       x/8=y.875
; 5 14352 6 x/8=y.00
; 4 14353 5 x/8=y.125
; 3 14354 4 x/8=y.25
; 2 14355 3       x/8=y.375
; 1 14356 2 x/8=y.50
; 0 14357 1 x/8=y.625
; 0 14358 0      x/8=y.75
; 6 14359 7            x/8=y.875
; 5 14360 6      x/8=y.00
; 4 14361 5            x/8=y.125 j.needle
; 3 14362 4      x/8=y.25
; 2 14363 3      x/8=y.375
; 1@16384 14364 2      x/8=y.5   63×228 halve start !!
; 0      *14365 1      x/8=y.625
; 0      *14366 0_NO_delay   x/8=y.75
; 6      *14367 7      x/8=y.875
;5<0+ 5      *14368 6   .0 >+6>6       <| check
;5<1+ 4       14369 5         .1 >+5>6        | apparent
;5<2+ 3       14370 4   .2 >+4>6        | number
;5<3+ 2       14371 3   .3 >+3>6        | cycle
;6<5+ 1       14372 2   .5 >+2>7        | in 
;6<6+ 0       14373 1   .6 >+1>7        | Cycle
;6<7 0       14374 0_NOdelay .7 >+0>7        | +2A/+3
;14< 6       14375 7   .8 >+7>15 >>6  >| ONLY

; every (7th and) 8th cycle are 'UN'contended= NOT-delayed !!!!!!


; my own calc says:
; 19/8=2.375  8*0.375 x=3  > ut=+2
; 20/8=2.5    8*0.5   x=4  > ut=+1
; 21/8=2.625  8*0.625 x=5  > ut=+0
; 22/8=2.75   8*0.75  x=6  > ut=+0

; 19=10011  >  011 >> 100 = 4  -2=    2 ula 
; 20=10100  >  100 >> 011 = 3  -2=    1 ula
; 21=10101  >  101 >> 010 = 2  -2=    0 ula
; 22=10110  >  110 >> 001 = 1  -2=-1 =0 ula
; sync idea  IN a,(254)=11tstate and contended ?? 128k port 254 is UNcontended :)

;          screentime    bordertime
;@14364 14364+128=14492 +100 =14592    128-228
;            +128=14720 +100 =14820    356-456 noncontention

hmm, does not look very readable anymore, the tabs seems a bit wrong now
i tryed a double-screen pixel rotate and the ATTR is difficult
Post Reply