News:

PlayBASIC2DLL V0.99 Revision I Commercial Edition released! - Convert PlayBASIC programs to super fast Machine Code. 

Main Menu

PlayBASIC V1.64O (Work In Progress) Gallery

Started by kevin, January 27, 2013, 10:50:31 PM

Previous topic - Next topic

kevin





PlayBASIC V1.64O  (Work In Progress) Gallery (January 27, 2013)


    This thread  documents the changes made for the PlayBASIC 1.64 revision O retail upgrade.  

  This upgrade was released (9th,Aug,2013)



Upgrade History


    For newer upgrade work in progress see,

    See  PlayBASIC V1.64P (login required)   -     Convert PlayBASIC To Machine Code Dll's


    For older upgrade work in progress see,

    See  PlayBASIC V1.64N2 & V1.64N3

    See  PlayBASIC V1.64N

    See  PlayBASIC V1.64M

    See  PlayBASIC V1.64L Learning Edition History (Building learning Edition Thread)

    See  PlayBASIC V1.64L





Upgrade Work in Progress (Blog)




PlayBASIC V1.64O Beta1 - Dynamic Function Calling

     While under the hood, figured I'd tweak the searching up a little more in the CallFunction operation.  If you call a function by name, then it has to search through the function names looking for a match.  The search it self is nothing fancy, it's just a linear search, so figured it'd be a handy place for a hash level pre-screen.  
With the hash,  V1.64O it's about 40% quicker than V1.64N3 using the original bench mark code.




PlayBASIC Code: [Select]
 Print "Dynamic Psub Calling With Parameter"

Dim FunctionNames$(3)
Dim FunctionIndexes(3)

FunctionNames$(0)="Test0"
FunctionNames$(1)="Test1"
FunctionNames$(2)="Test2"
FunctionNames$(3)="Test3"

FunctionIndexes(0)=FunctionIndex("Test0")
FunctionIndexes(1)=FunctionIndex("Test1")
FunctionIndexes(2)=FunctionIndex("Test2")
FunctionIndexes(3)=FunctionIndex("Test3")


Global Value0
Global Value1
Global Value2
Global Value3

MaxTests=10000

Do
Cls 0

frames++

t=timer()
for lp=0 to MaxTests-1
CallFunction FunctionNames$(lp &3),lp
next
tt1#+=(timer()-t)
print tt1#/frames
print "tests:"+STR$(lp)

t=timer()
for lp=0 to MaxTests-1
CallFunction FunctionIndexes(lp &3),lp
next
tt2#+=(timer()-t)
print tt2#/frames
print "tests:"+STR$(lp)

print fps()
print Value0
print Value1
print Value2
print Value3


Sync
loop




Psub Test0(a)
Value0++
EndPsub

Psub Test1(a)
Value1++
EndPsub

Psub Test2(a)
Value2++
EndPsub

Psub Test3(a)
Value3++
EndPsub





Update:

     Updated the search routine again, stripping another 5->6 milliseconds from the earlier update.    I'd still strongly encourage user to pre-compute the function index prior, rather than dynamically searching for the function name (as a string) every single time.  But it's viable either way.  




kevin

#1
PlayBASIC V1.64O Beta1 - Download

    Here's today's build of the V1.64O.   Not too sure what else will make it into this upgrade,  so it might be while before there's a final.  

    removed, newer beta bellow

kevin

#2
 PlayBASIC V1.64O Beta2 - Small Tweaks

     Add a couple of tiny  tidbits into today's build, the first is a constant to return the current Optimizer state.  (PBOptimizeState),  which allows a include to set the optimizer state it wants/requires without changing the state for the rest of the program.  To do that, you just preserve the state in constant on entry to the code block then restore it at the end.



PlayBASIC Code: [Select]
   ; remember the current optimizer state   
COnstant PreServeOptimizeMode = PbOptimizeState


; Enable Type Caching and general optimizations
OptExpressions 3


; print Optimizer stat within this block of code
print PbOptimizeState




; restore it at the end of this block of code
OptExpressions PreServeOptimizeMode


; print the optimizer state here
print PbOptimizeState


Sync
waitkey


 



 64bit Start Interval / End Interval (High Resolution timing)

     Dropped a couple of functions in to query the number of high res ticks between the pair of calls.   The first call stamps the start time, and the End call gets the number of the ticks that has past since the start call.  Internally the timer resolution is 64bit, so the routine returns the interval in 32bit.   On my system the high res timer is about 1000 ticks the resolution of the milliseconds.    It'll actually be different for different CPU's...  But ya get that..

     The Functions use an internal array for storing up to 128 (at this time) unique time points.  Will most likely reduce that to 32 or something.   The high resolution time is just like the millisecond timer,  it's counting up regardless of what app is currently being executed.

PlayBASIC Code: [Select]
   Max=25000

Do
cls

frames++


; Set the starting time, so we can time the number of hi
; resolution ticks between the pair of calls
StartInterval(0)

; get the current millisecond when the loop starts
timeStart=timer()

; do a loop for something to time
For lp =0 to Max
a=b
next

; get the number of low res / milliseconds that haver past
Time1=Timer()-TimeStart

; get the high resolution of ticks that have past
time2=EndInterval(0)

tt1#+=Time1
tt2#+=Time2

print " Average Ticks:"+str$(tt1#/frames)
print "Average Hires Ticks:"+str$(tt2#/frames)

sync
loop







monkeybot

ooh! i like the sound of that,good for a code profiler maybe?

kevin

#4
Quoteooh! i like the sound of that,good for a code profiler maybe?

  go for it.


PlayBASIC V1.64O Beta3 - String Fixes

  Dunno how long this one been hanging around, but looking at the source i'd say forever.   Anyway today's little issue was found in the CutRight$() function, when the cut point is less than the first character. Previously it'd return the entire string, now it returns a null string like it should.    I suspect the same fault occurs with cut left also.  Assuming they're cut and paste of each other..  


PlayBASIC Code: [Select]
   s$="playBASIC"

print "CutRight$"
for lp =0 to len(s$)+10
print str$(lp)+CutRight$(s$,lp)
next
print ""
print ""
print ""

print "CutLEft$"

for lp =0 to len(s$)+10
print str$(lp)+CutLeft$(s$,lp)
next

print ""
print ""
print ""

Sync
waitkey





  Edit:  Yes, both functions had similar issues, both run correct now.



monkeybot


kevin

#6
Quoteare you going to put beta 2 up?

   It no longer exists.


PlayBASIC V1.64O Beta3 - Download

    Here's today's build of V1.64O.

    removed, newer beta bellow



kevin

#8
PlayBASIC V1.64O Beta4

   Just testing an alternative version of the RGB function, since the standard version  expects the 0-255 values for the R components, however sometimes it's easy to use floating point representations in some algorithms.   So in those cases you'd need to mult each component scaler by the 255..  Like so   Rgb(255*R_Level#,255*G_Level#, 255*B_Level#) .   The problem with this is two fold, first you've got the VM running 3 extra floating point mults plus there's no bounds clipping.    

   Performance wise the test function is about 40% faster, which should be handy little gain given it'd generally only be used in brute force loops.   Currently it's called RGB2,  Dunno what i'll actually be called  though..  

PlayBASIC Code: [Select]
   max=10000

Do
cls

frames++

t=StartInterval(1)
For lp=0 to max
col1= RGB(red# * 255.0, green# * 255.0, blue# * 255.0)
next
tt1#+=EndInterval(1)
print tt1#/frames


t=StartInterval(1)
For lp=0 to max
col1= RGB2(red# , green# , blue# )
next
tt2#+=EndInterval(1)

print tt2#/frames

print Fps()

Sync
loop





RayRayTea2

#9
It seems the collision against the tiles with RectHitMap leaks on top and bottom of every tile.

To see the effect load the attached file and try to run it. Move the mouse so the rectangular shape gets close to the tiles. If there's a tile above or to the right of the Rectangle, it will report a collision one tile before it actually happens.

Uncomment line 9 in the "Workers.pba" and comment out line 10 and it'll work correctly... The difference between the two files "tileset.png" and "tileset tweak.png" is that the "tweak" one has top and left row and column of pixels deleted.


The collision still gets triggered with a one pixel difference depending on where you approach the tile from, this can also be seen with shapes and ShapeHitMap. In Workers.pba uncomment line 9 and comment out line 10 , in "Main.pba" uncomment lines 17-20 and comment out lines 23-27 (also uncomment line 22 in SetUp.pba otherwise it'll crash! - this was already reported elsewhere so let's ignore it for now), and you'll see that a collision with a (rectangular non rotated) shape is checked slightly differently depending on whether it's checked against top and left side of a shape or bottom and right sides.

Top and Left side do not report a collision until the shape actually enters into a map tile, while Top and Right sides report a collision as soon as they are one pixel next to a map tile.

Edit: clarification.

Edit2: Weird, in this image the rectangle is not even touching the green area yet it triggers the collision, while this one's almost touching the red area and not reporting anything.

kevin


PlayBASIC V1.64O - Doc Builder V0.80 Updated

   Been making some updates to the documentation and the documentation builder most of this week. The doc's are written in a kind of markup language that you'd find used in most forum software. The PB + UW web sites use a similar set of tags for the text. So text can be moved between sites without always having to reformat them for display.

  Some tags that sites use that doc's didn't would be things font sizing and colour tags. So if we dragged some text over from the forum into the doc's they'd have to be reformatted. Pretty tedious stuff, where it's easier to just drop some code into the document parser in the builder.

  The doc builder isn't updated very often, so when cracking open the project, it was soon obvious the parser was written to be quickly thrown to together, rather than easy to update. Most of the tags, it just use replaces$ statements on the raw text. Which is OK, but there are some situations where that approach fails (like when a tag contains a keyword another tag uses). So decided to write a more general purpose parser that new tags could be dropped into without logical problems.

  The updated solution scans through the document looking for tags, when it finds a possible tag it attempts to decode it. If it's a known, we call the response function, if not, ignore and keep scanning. The parser supports all the old stuff (mostly just cut'n'pasted into the new routine) like automatic cross referencing of local links, pictures, indentation, inner menus and syntax highlighting PlayBASIC code blocks, through to a hand full of new tags for Font sizes and color controls. Which just improve the styling of the information. And when there's 1276 pages of documentation, we need all the styling help we can get.

  Some other changes are better project copying support when building the manual. Previous versions would only copy projects with a single main source file. So example projects attached to articles can now have as many files as the author likes. Another addition that I can't believe hasn't made it's way into the tool sooner, is support for creation and edit dates within the articles. Which might not seem all that useful now, but we can finally track what articles are likely to be different between manual builds.

  Anyway all this stuff will appear in the V1.64O upgrade at some point.



kevin

 PlayBASIC V1.64O - Docs Docs Docs

    Progress has been pretty slow on all fronts recently, still trying to wedge the odd documentation pass in wherever possible.   Most sessions seem to focused around running the global replacement tool over the various command sets.   The only problem with global replacements is they're indiscriminate.   Making It a bit of a skill catching the various typo combinations without breaking other sections.  The up side is that's pretty quick even though it's written in PlayBASIC classic. 

    It's not all about typo's though, there's a number of abbreviations that pop up throughout the manual, generally used within a hand full of variations.   So I've been trying to catch them where ever possible.   It actually needs some kind of glossary of terms also, just to keep it all self contained.    Ideally so when it's finally put online it'll get more links in, than out.     Some of that stuff could just be on the PB.com site though.   Lots of terminology being thrown around that apparently almost nobody understands.

   One thing the replacement tool doesn't handle though, is parsing the associated PlayBASIC examples that each articles may have.   The doc's are really just a series of folders, each folder is a command set/region of the manual.   Within each area, each command has it's own folder for it's attached projects.  The replacement tool only looks at the article though, it doesn't load and parse attached project also, in fact it has no ideas about this concept.   Meaning errors can't be trapped in the attached source files.

   Not 100% sure when it'll be ready,  but with the holidays fast approaching that should help things along.   Probably only a few more hour sessions in it..  We'll see..


kevin


PlayBASIC V1.64O  - Docs Update (Beta)

      Just put today's build on the docs of the help online.  There's a bit of new stuff hidden away in there, but basically it's had various replacement passes run over it.   Hopefully they haven't broken anything in process, but that's certainly possible.    Mainly interesting in broken examples, so if you could pick them and test them that'd be most helpful. 

     Get Documentation Update (login required)



kevin

#13
  Mapping Bits To Palette Indexes

   One by-product of the Spectrum emulator thread was call back to an even older idea for mapping bit groups out at palette mapped chunky pixels.   Translating 1 ->2 bit planar frame buffers from some legacy platforms like the Spectrum + C64 etc etc is bit of a mouth full for the runtime to handle, without 'building' a complete render solution.  It's not just legacy video hardware, but these little tidbits pop up when loading legacy file formats also. (Example  Where all you're doing it taking a byte, and rendering a pixel out for each bit or pair of bits.  

   Now if speed is absolutely desirable, then generally i'd build jump table generator for such things.   Where each of the possible byte values is mapped to a hand rolled set of DOT commands.    This works pretty well, but even in the leanest inner loops there's still a lot of VM + pixel write overhead.    I suspect the majority of that could be removed by building a command will draw dots from a user defined palette, where it selects the colour by rolling and masking the bit pattern.   So you could render each bit as pixel or groups of bits as pixels.

   A bit like this,

PlayBASIC Code: [Select]
      Global PaletteAddress
Dim Palette(256)
PaletteAddress=GetArrayPtr(Palette(),true)


Palette(0)=$ff0000
Palette(1)=$ffffff
Palette(2)=$00ffff
Palette(3)=$0000ff

t=timer()

print "Single Pixel"
Lockbuffer
for lp=100 to 110 step 2
PM_DOT_ROLBITMASKB(400,lp, %01111111,1,%00000001,8)
next
unLockbuffer


print "Double Pixel"
Lockbuffer
for lp2=lp to lp+10 step 2
PM_DOT_ROLBITMASKB(400,lp2, %00110110,2,%00000011,8)
next
unLockbuffer

print timer()-t



Sync
waitkey


; -------------------------------------------------------------------
; ROR AND DRAW PALETTE MAPPED DOTS
; -------------------------------------------------------------------

Psub PM_DOT_ROLBITMASKB(Xpos,Ypos, ThisByte,ShiftDistant,Mask,RunLength)

For lp=1 to RunLength
ThisByte=Rol8(ThisByte,ShiftDistant)
; print bin$(ThisByte)

col=Palette(ThisByte and Mask)
; Draw the dot 4 times it's actual size so we can see it
Dotc Xpos ,Ypos,col
Dotc Xpos+1,Ypos,col
Dotc Xpos+2,Ypos,col
Dotc Xpos+3,Ypos,col

Ypos2=Ypos+1
Dotc Xpos ,Ypos2,col
Dotc Xpos+1,Ypos2,col
Dotc Xpos+2,Ypos2,col
Dotc Xpos+3,Ypos2,col

Xpos+=4
next

EndPsub




     A long & word sized palette version would be handy also, then you could palette map your sprites and encode/decode then in some bizarre format and load them without as much brute force overhead.  



PlayBASIC Code: [Select]
      Global PaletteAddress
Dim Palette(256)
PaletteAddress=GetArrayPtr(Palette(),true)


Palette(0)=$ff0000
Palette(1)=$ffffff
Palette(2)=$00ffff
Palette(3)=$0000ff


Xpos =100

For Chr=0 to 1
Ypos=100

Lockbuffer

for ScanLine=0 to 7
ThisByte=ReadData()
PM_DOT_ROLBITMASKB(Xpos,Ypos+(ScanLine*2), ThisByte,1,%00000001,8)
next
unLockbuffer

Xpos+=8*4+10

next


Sync
waitkey



; -------------------------------------------------------------------
; ROR AND DRAW PALETTE MAPPED DOTS
; -------------------------------------------------------------------

Psub PM_DOT_ROLBITMASKB(Xpos,Ypos, ThisByte,ShiftDistant,Mask,RunLength)

For lp=1 to RunLength
ThisByte=Rol8(ThisByte,ShiftDistant)
; print bin$(ThisByte)

col=Palette(ThisByte and Mask)
; Draw the dot 4 times it's actual size so we can see it
Dotc Xpos ,Ypos,col
Dotc Xpos+1,Ypos,col
Dotc Xpos+2,Ypos,col
Dotc Xpos+3,Ypos,col

Ypos2=Ypos+1
Dotc Xpos ,Ypos2,col
Dotc Xpos+1,Ypos2,col
Dotc Xpos+2,Ypos2,col
Dotc Xpos+3,Ypos2,col

Xpos+=4
next

EndPsub


Memory:
Data %11111110
Data %10000001
Data %10000001
Data %10000001
Data %11111110
Data %10000000
Data %10000000
Data %10000000

Data %11111110
Data %10000001
Data %10000011
Data %11111100
Data %11111100
Data %10000011
Data %10000001
Data %11111110






 Couldn't help it..  A C64 mock up...  

      Dropped a bare bones version of the routines into PB, ripped the character set and quickly knocked up a C64 display emulation.  The screen is draw in 1by1 and scaled up to fit the screen a bit better.  Memories..


 Edit #1: Can almost double the performance of the naive version by fetching the character set bitmap in longs rather than bytes.   The size of the fetch is helpful in PB, but by caching the value in an integer and then scrolling the bits via division (quicker than a function call), we get a lower latency per 8 pixel strip.    Shown in the second picture.  

    So to render a 8*8 pixel square we end up with this,
PlayBASIC Code: [Select]
                        ThisLong=PeekBankInt(CharMapRomBank,Address)
Address+=4

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong,1,%00000001,8)
Ypos2+=1

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$100,1,%00000001,8)
Ypos2+=1

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$10000,1,%00000001,8)
Ypos2+=1

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$1000000,1,%00000001,8)
Ypos2+=1


ThisLong=PeekBankInt(CharMapRomBank,Address)
Address+=4

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong,1,%00000001,8)
Ypos2+=1

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$100,1,%00000001,8)
Ypos2+=1

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$10000,1,%00000001,8)
Ypos2+=1

VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$1000000,1,%00000001,8)





  Edit #2: By pre-computing the vertical offsets per row, we squeeze another 20-25 odd fps out of such a refresh.   So the inner character rendering loop is down to approximately  18 or so PB VM  instruction calls per 64 pixels rendered.     Some of them optimize away, but it's a reasonable indicator.   Not all instructions execute in the same time though.   

PlayBASIC Code: [Select]
      rendertoimage screen
Lockbuffer
ThisRgb=Point(0,0)
Ypos=0
For ChrYLP =1 to 200/8
Xpos =0

Ypos1=Ypos
Ypos2=Ypos+1
Ypos3=Ypos+2
Ypos4=Ypos+3
Ypos5=Ypos+4
Ypos6=Ypos+5
Ypos7=Ypos+6
Ypos8=Ypos+7

For ChrXLP=1 to 320/8
ThisLong=PeekBankInt(CharMapRomBank,Address)
Address+=4

VGFX_PM_DOT_RBMB(Xpos,Ypos1, ThisLong,1,%00000001,8)
VGFX_PM_DOT_RBMB(Xpos,Ypos2, ThisLong/$100,1,%00000001,8)
VGFX_PM_DOT_RBMB(Xpos,Ypos3, ThisLong/$10000,1,%00000001,8)
VGFX_PM_DOT_RBMB(Xpos,Ypos4, ThisLong/$1000000,1,%00000001,8)

ThisLong=PeekBankInt(CharMapRomBank,Address)
Address+=4

VGFX_PM_DOT_RBMB(Xpos,Ypos5, ThisLong,1,%00000001,8)
VGFX_PM_DOT_RBMB(Xpos,Ypos6, ThisLong/$100,1,%00000001,8)
VGFX_PM_DOT_RBMB(Xpos,Ypos7, ThisLong/$10000,1,%00000001,8)
VGFX_PM_DOT_RBMB(Xpos,Ypos8, ThisLong/$1000000,1,%00000001,8)


Xpos+=8
next
Address&=$7ff ; Keep Address within $7ff

Ypos+=8
next
unLockbuffer






 

kevin


  PlayBASIC V1.64O  Beta 5- Dll Binding Tests

       In PlayBASIC we can use system & custom external DLL's in a handful of ways, from dynamically calling the functions (CallDLL) through to binding them (via LinkDLL) so they appear as if they're internal functions.    The latter is better solution since the function pointers are resolved before program execution starts.  When we use CallDLL, the operation has to solve the function pointer each call.    It's not a huge overhead, but an overhead none the less. 

       Using DLL's can have a few issues tho, most notably that windows doesn't provide a native 'load from memory'  functionality.  So  If you write a custom expansion dll, then you're basically giving this code away every time you share the final program.   In newer prototypes of the runtime we've solved this problem already,  but i've been wondering if it'd work in the legacy runtime at all ?  And Yes.. it does.. sort of :)

       So tonight's testing has been focusing on wedging the alternative loader layer into the runtime.  In the test any dll linked with linkdll, is pre loaded into a chunk of memory and then manually initialized for execution.  It's just defaulting to this behavior since it's the least amount of work required.   After a few little catch 22 hiccups the test dll's seems to be working as normal.

       Therefore, it appears that we should be able to bind custom dll's (dlls your program uses, NOT PB DLL's) into final EXE.    There's probably some DLL's where this won't work (like wrappers of wrappers), but ya get that !