Posts: 806
Threads: 135
Joined: Apr 2009
Reputation:
5
This is interesting. There's quite a lot of overhead in PLOT, I think - this is fairly unoptimized, still - and appears to be a little buggy. It also doesn't use the screen tables lookup yet. But it's late and I need to go to bed
Code: SUB plotPoint (x as uByte, y as uByte)
ASM
ld d,(IX+5) ;'X
ld e,(IX+7) ;'Y
ld a, 191
sub e
ret c
ld e, a
and a
rra
scf
rra
and a
rra
xor e
and 248
xor e
ld h, a
ld a, d
rlca
rlca
rlca
xor e
and 199
xor e
rlca
rlca
ld l, a
ld a, d
and 7
ld b, a
inc b
ld a, 1
plotPoint_loop:
rrca
djnz plotPoint_loop
;cpl
ld b, a
ld a, (hl)
or b
ld (hl), a
END ASM
END SUB
FUNCTION t() as uLong
asm
DI
LD DE,(23674)
LD D,0
LD HL,(23672)
EI
end asm
end function
dim time0, time1, time2 as long
dim n as uInteger
cls
for n=1 to 150
plotPoint(n,n-1)
plot n,n+3
next n
time0=t()
for n=0 to 50000
plot 50,50
next n
time1=t()
for n=0 to 50000
plotPoint(50,50)
next n
time2=t()
print "ZX Basic 50,000 plot:"
print time1-time0;"frames =";(time1-time0)/cast(float,50);" seconds"
print
print "plotPoint 50,000 times:"
print time2-time1;"frames=";(time2-time1)/cast(float,50);" seconds"
Posts: 282
Threads: 48
Joined: Feb 2011
Reputation:
0
nice, i got 11 secs for zxbasic and 7 secs for your function
I cant seem to get any colour of dots except black
Code: SUB plotPoint (x as uByte, y as uByte)
ASM
ld d,(IX+5) ;'X
ld e,(IX+7) ;'Y
ld a, 191
sub e
ret c
ld e, a
and a
rra
scf
rra
and a
rra
xor e
and 248
xor e
ld h, a
ld a, d
rlca
rlca
rlca
xor e
and 199
xor e
rlca
rlca
ld l, a
ld a, d
and 7
ld b, a
inc b
ld a, 1
plotPoint_loop:
rrca
djnz plotPoint_loop
;cpl
ld b, a
ld a, (hl)
or b
ld (hl), a
END ASM
END SUB
FUNCTION t() as uLong
asm
DI
LD DE,(23674)
LD D,0
LD HL,(23672)
EI
end asm
end function
dim time0, time1, time2 as long
dim n as uInteger
cls
for n=1 to 150
plotPoint(n,n-1)
plot n,n+3
next n
time0=t()
Paper 5
INK 2
for n=0 to 191
for y=0 to 191
plotPoint(n,y)
next y
next n
time1=t()
Paper 3
INK 4
for n=0 to 191
for y=0 to 191
plot y,n
next y
next n
time2=t()
print "plotpoint 50,000 plot:"
print time1-time0;"frames =";(time1-time0)/cast(float,50);" seconds"
print
print "zxbasic 50,000 times:"
print time2-time1;"frames=";(time2-time1)/cast(float,50);" seconds"
On the second pass only the green paper shows up
Posts: 806
Threads: 135
Joined: Apr 2009
Reputation:
5
You know, looking at this, I'm particularly impressed with this bit:
Code:
rra
scf
rra
and a
rra
xor e
and 248
xor e
As we know, the bit pattern for a screen address is 010LLrrr LLLCCCCC - where L = character line number (0-31), r=row in character. C=column.
This rotates in the 010, and slides over the two first line bits LL.
Then it does something really clever. It puts in the last 3 bits from the original, left in e. I'd have probably done something like:
Code: RRCA
RRCA
RRCA
AND %010110000
ld d,a
ld a,e
and 7
or d
Which is far more faffing. XOR/AND/XOR. How cool is that for three instructions to merge some bits of one register with another? New trick learned.
Posts: 1,838
Threads: 56
Joined: Aug 2019
Reputation:
25
slenkar Wrote:nice, i got 11 secs for zxbasic and 7 secs for your function ZX Basic uses ROMs PLOT (which is already somewhat optimized, BTW!), but uses a different entry point, to allow 192 scanlines.
On the other hand, DRAW has already been optimized and no longer uses PLOT, but PIXELADDR for the 1st point of a scan line (remaining points are computed relatively to the last plotted dot).
Also, keep en mind that ZX Basic/ROM PLOT routine also updates ATTR according to TEMP ATTRs and also take into account the SCREEN_ADDR variable (so you can draw/print in another memory/region like a temporary buffer).
Posts: 806
Threads: 135
Joined: Apr 2009
Reputation:
5
slenkar Wrote:nice, i got 11 secs for zxbasic and 7 secs for your function
I cant seem to get any colour of dots except black
On the second pass only the green paper shows up
The routine, as it stands, just sets the ink point on - it doesn't touch attributes, change the current plot values or any such thing - it's optimized to get that point changed, and do nothing else. Slenkar - if you did a CLS after setting ink and paper values, you'd get what you were looking for, since that would change all the attribute data on the screen for you.
As Boriel points out, the standard plot routine also changes the attribute value and does some housekeeping in the background. That said, it's pretty rare that a draw needs to do this, since the effect is usually terrible. I can't think of any games that would require it - usually all the attribs in the game area are set already.
It might be reasonable to set up a fastplot and fastdraw routine for games purposes, that don't do the overhead. If so, it would be a plot similar to this, an absolute draw (from x1,y1 to x2,y2 - no relative movement), and routines to change the ink and paper in an area block - which would go with the clearblock routine.
The reason for not using relative draw is if you were working with a vector game, you'd generate the vertices explicitly, so a draw from vertex point 1 to vertex point 2 is probably more useful.
Posts: 806
Threads: 135
Joined: Apr 2009
Reputation:
5
Code: SUB plotPoint (x as uByte, y as uByte)
ASM
ld d,a ;'X
ld a, 191
sub (IX+7) ;' y
jr c, plotPoint_end
ld l,a
ld h,ScreenTables/256
ld a,(HL)
inc h
ld l,(HL)
ld h,a
; now we're on the right row on screen.
ld a,d
RRCA ; divide column by 8 for bytes.
RRCA
RRCA
AND 31
add a,l
ld l,a
ld a, d
and 7
ld b, a
inc b
ld a, 1
plotPoint_loop:
rrca
djnz plotPoint_loop
ld b, a
ld a, (hl)
or b
ld (hl), a
plotPoint_end:
END ASM
END SUB
Using screen address tables shaves this down to 6.42 seconds for 50,000 points plotted. That's not too bad, all told.
(screentables.asm is available elsewhere in the forum, I promise!)
Considering that quite a few routines can use the screen lookup tables, 512 bytes of screen tables isn't crazy for a solid speedup (and of course, if you are using a shadow screen, then you could either rewrite a bit, or make screen tables that point to your shadow screen memory).
Not sure requiring rotate tables, which is much bigger, is a win, here for one loop removal.
Posts: 282
Threads: 48
Joined: Feb 2011
Reputation:
0
ive never required any color dots than black anyway i suppose,
the zxbasic plot doesnt seem to draw colored dots either I dont think.
those lookup tables really seem worth using
Posts: 615
Threads: 49
Joined: Feb 2009
Reputation:
2
Uncontended Memory: ZXBC Plot: 11 Sec. Britlions FastPlot: 7.7 sec
Contended Memory: ZXBC Plot: 12.1 Sec. Britlions FastPlot: 9.1 sec
Impressive!!!
Posts: 1,838
Threads: 56
Joined: Aug 2019
Reputation:
25
slenkar Wrote:ive never required any color dots than black anyway i suppose,
the zxbasic plot doesnt seem to draw colored dots either I dont think.
those lookup tables really seem worth using It does (otherwise, it would be a bug). ZXBC tries to mimic Sinclair BASIC command as much as possible while trying not to increase the overhead.
BTW impressive measures!
Posts: 806
Threads: 135
Joined: Apr 2009
Reputation:
5
Slenkar: Perhaps these are useful for setting colours?
They both paint a rectangle in the specified colours - one needs ink/paper/bright/flash separately, the second takes the attribute byte directly.
Code: SUB WindowPaint(x as uByte,y as uByte, width as uByte, height as uByte, inkCol as ubyte, paperCol as uByte, isBright as uByte, isFlash as uByte)
paint(x,y,width,height,(isFlash<<7+isBright<<6+paperCol<<3+inkCol))
END SUB
Code: SUB paint (x as uByte,y as uByte, width as uByte, height as uByte, attribute as ubyte)
asm
ld a,(IX+7) ;ypos
rrca
rrca
rrca ; Multiply by 32
ld l,a ; Pass to L
and 3 ; Mask with 00000011
add a,88 ; 88 * 256 = 22528 - start of attributes. Change this if you are working with a buffer or somesuch.
ld h,a ; Put it in the High Byte
ld a,l ; We get y value *32
and 224 ; Mask with 11100000
ld l,a ; Put it in L
ld a,(IX+5) ; xpos
add a,l ; Add it to the Low byte
ld l,a ; Put it back in L, and we're done. HL=Address.
push HL ; save address
LD A, (IX+13) ; attribute
LD DE,32
LD c,(IX+11) ; height
BLPaintHeightLoop:
LD b,(IX+9) ; width
BLPaintWidthLoop:
LD (HL),a ; paint a character
INC L ; Move to the right (Note that we only would have to inc H if we are crossing from the right edge to the left, and we shouldn't be needing to do that)
DJNZ BLPaintWidthLoop
BLPaintWidthExitLoop:
POP HL ; recover our left edge
DEC C
JR Z, BLPaintHeightExitLoop
ADD HL,DE ; move 32 down
PUSH HL ; save it again
JP BLPaintHeightLoop
BLPaintHeightExitLoop:
end asm
END SUB
|