Topic : The GFA-Basic Compendium
Author : GFA Systemtechnik GmbH
Version : GFABasic.HYP v2.98 (12/31/2023)
Subject : Documentation/Programming
Nodes : 899
Index Size : 28056
HCP-Version : 3
Compiled on : Atari
@charset : atarist
@lang :
@default : Document not found
@help : Help
@options : +g -i -s +z
@width : 75
@hostname : STRNGSRV
@hostname : CAB
@hostname : HIGHWIRE
@hostname : THING
View Ref-FileVDI Revisited
by
Rev 6 6/10/2022
Another look at the VDI + GFA, take two :o)
Can anything else be done to get even more performance out of the VDI + GFA?
Actually, the answer is yes. First some background information.
GFA actually has 2 sets of AES/VDI parameter blocks. The 1st set is for the
coder and custom bindings, aka INTIN/INTIN() and friends. The 2nd set is for
all built-in VDI commands. GFA does't normally give access to it's internal
parameter blocks. This scheme keeps the built in commands from clobbering the
user parameter block contents.
I discovered this a very long time ago and forgot to document it in my
GFABASIC.hyp:
GB +44 contrl 6 words
GB +48 global 15 words (shared, same as GB+4)
GB +52 gintin 20 words
GB +56 gintout 20 words
GB +60 addrin 10 longs
GB +64 addrout 10 longs
GB +68 contrl 12 words
GB +72 intin 128 words
GB +76 ptsin 256 words
GB +80 intout 128 words
GB +84 ptsout 30 words
Hidden on the end of the GB structure is 10 extra pointers. These extra
pointers point to GFA's internal AES/VDI arrays! These have been there since v3
and perhaps even in v2, I have not looked. They are certainly valid for v3
regardless. I suppose the next question is, how is this related? The answer
is simple, now you can snoop the results of all built-in AES/VDI calls.
Interesting, yes?
The other thing you need to keep in mind, the built in graphics commands are
hands down faster than any binding you can write, since the parameters are
register based. Most of them are 100% clean VDI calls, especially the DEFxxx
commands and graphics primitives. A command like this 'DEFLINE ,x' where a
parameter is omitted (line style) only generates code for that one parameter.
The compiler is very efficient in this regard.
Thus 'DEFLINE ,1' compiles to a single call to vsl_width(1)
Typically if you need the result of some VDI call, you would be forced to write
a binding. Let's use the command vsl_width() as an example, it returns the
actual width that was set. In the past if you wanted to know the result, then
you ran in trouble.
DEFLINE ,x !no return value of course
' so you do this
FUNCTION vsl_width(c&)
INTIN(0)=c&
VDISYS 16,0,1
RETURN PTSOUT(0)
ENDFUNC
This is all well and good, but now you can do this:
FUNCTION vsl_width(c&)
DEFLINE ,c& !set only the width
RETURN WORD{LONG{GB+84}} !snoop GFA's internal PTSOUT(0)
ENDFUNC
This will actually outperform the short VDI binding. I did some benchmarking
with Hatari, since aranym can't be trusted at all.
It's possible to push it even faster, if you don't mind using some global
variable:
ptsout_%=LONG{GB+84} !initialize this somewhere in your app startup
FUNCTION vsl_width(c&)
DEFLINE ,c&
RETURN WORD{ptsout_%} !use the global instead
ENDFUNC
Using the global gains even a bit more speed.
If you need maximum speed just throw away the pretty vsl_width() wrapper and
use the code directly where needed. It will go even faster still. Remember user
coded subroutines use the stack for parameter passing, so the mere pushing of
the parameters slows it down.
Dealing with extra workstations is another potential area to improve
performance. A lot of people write bindings that pass the workstation handles.
Perhaps the manual was never clear on this, but GFA pre-loads CONTRL(6) with
the default handle for the workstation it opens at startup. It also keeps a
backup copy of this handle in case it gets lost. I assume the thought process
is this. I need to do some VDI calls on a different workstation, therefore I
must use a bunch of custom bindings. This is really not the case at all. GFA
has a handy way of sending all VDI calls to any open workstation, even custom
bindings so long as they don't touch CONTRL(6).
A bit of pseudo code:
handle=@v_opnbm(... !offscreen buffer (especially a workstation)
' let's draw to it without using any custom bindings
V~H=handle !send all vdi calls offscreen
CLIP 0,0,w&,h& !vs_clip()
COLOR ... !vsl_color()
DEFLINE ... !vsl_type()
LINE ... !v_pline()
BOX ... !v_bar()
CIRCLE... !etc..
CLIP OFF !you get the idea,
V~H=TRUE !undo redirection, restore internal handle from backup copy
' blit it to the screen
~@v_clsbm()
Not only is this much smaller compiled, but it's far quicker than a bunch of
custom bindings which pass handles. I use this method in my Boing demo to
pre-render all the frames and animate the GEM window.
It goes without saying, the speeds up here are small, but on slower hardware
every little bit adds up.
If you are using a binding for a built in command because you think it's broken
somehow, please do report it. Bugs must to be eradicated. Happy VDI coding. ;o)