PlayBASIC V1.64N2 / V164N3 (Work In Progress) Gallery

Started by kevin, April 22, 2012, 12:07:12 AM

Previous topic - Next topic

kevin

#30
  PlayBASIC V1.64N2  Beta #12 - Caching Seems Stable

        The more code I test, the more stable ti all seems with issues generally only occurring due to by product of the runtime allowing the user to read from none existent type structures.    While not feature I'm a huge fan of, we're basically stuck with it today.   Dunno what that is ?,  well imagine we have an array of user defined types.   When we DIM the array we're creating the 'container' for the types to live within, but we're not actually creating individual types.  The individual Type structures aren't allocated until you either alloc one via NEW, or WRITE to the structure, which makes PB automatically allocate a type of the 'arrays type'.  

         Ie.
PlayBASIC Code: [Select]
           Type Stuff
Status
Name$
x,y
Score
EndType

Dim Things(100) as stuff

; Auto creation upon writing to a field
Things(50).Status = true
Things(50).Name$ = "Bill"

; or manual allocation
Things(60) = NEW STUFF
Things(60).Status = true
Things(60).Name$ = "Jenny"




     So after running the two writes, we end up with two shiny new types within our array.   All the others are yet to allocated, ie empty.   Now the thing is, often when iterating through a Typed array, we might end up with a loop that looks something like this.

PlayBASIC Code: [Select]
    For lp =0 to 100

if Things(lp).Status

print Things(lp).Name$

endif

Next





     Here the VM is polling every cell in our things() array.  Now since only two of them exist, wouldn't this give illegal accesses ?, Yeah, it should.. But It was decided that the VM should ignore those illegal reads, rather than pop a runtime error on them.    Now given we're talking about decisions from some 10 or more years ago, it's a bit difficult to revert that today,  without breaking older programs.  

     The solution is simple, rather than access the field of the type, we should always query the cell of the type to see if it exists or not.  If it exists the cell will be another other than zero, if it's not, it'll be zero.

     Like This,
     
PlayBASIC Code: [Select]
    For lp =0 to 100

; query this cell, for any value that's NOT zero, when it's not zero it must exist
if Things(lp)

print Things(lp).Name$

endif

Next



 
        This method is perfectly safe and is preferred structure of such loops today, but I don't think that was in the original editions.  So while a lot of modern code tests the existent of the structure prior to using it, other routines don't.   This is not a big deal in a world without caching or when it's disabled, but caching  only work consistently when the run time knows for sure the thing that was last accessed, exists.   So the legacy behavior, is whats making caching a little shakey on older programs.    

        Tried a version of the Vm tonight that doesn't allow reading from none existent types, but as expected,  an awful lot of legacy programs don't work.  So,  what I think i'll end up doing is just leaving the existing behavior in classic versions of PlayBASIC, and implement it in PBFX runtimes.   It'd less of a culture shock that way...  




kevin

#31
  PlayBASIC V1.64N2  Beta #12b - Mmmmm Caching :)

       After soooooo looooong...... tinkering with compiler/runtimes, there's not much in the PlayBASIC world that actually surprises me.  Often a lot of work goes into the smallest of changes,  sometimes we win some handy double digit performance back or expand something to make it that little more flexible, but such changes are generally pretty marginal.   So imagine the look on my face tonight by simply re-blocking the cache instructions in the runtime, wins us back more performance that i'd even hoped for.    So much I was initially assuming it was broken..  Couldn't possibly be down in the low teens.. But it is.

       The test I'm using is the same basic type bench mark as always (Shown back here ) The test just goes through and does a bunch of read/writes to a 1D/2D/3D types arrays.  Where each test is performed  25,000 times.   Now in previous versions of V1.64N2, caching has shaved from between 17% up to a staggering 30% of the V1.64N speed.    Which I was more than happy with to be honest.   But today's edition of  V1.64N2 beta 12b,  is  conservatively between 15-20% faster again.    The 3D array is basically twice as fast.

       Now even though the bench mark code is basically presenting a perfect situation for the optimizer to chew through the expressions, it'll certainly be able to improve the performance of your real world programs also.   Since  type usage is frequently serialized in programs, so if you have a loop that runs through and processes your game characters each frame (list or array) and there's multiple lines where the same structure is accessed (read /write), then those operations may  be anywhere from 25% to 50% faster..    The amount of time won back, really comes down to how frequently the loop is executed.  

       Attached we have the results from the test running on V1.64N, V1.64N2 Beta11 and V1.64N2 beta12b..   Speaks for itself really..  

ATLUS



kevin

#34
  PlayBASIC V1.64N2  Beta #12d - Download

       Well, here's todays build for you mess around with.  Pretty much completed Type Caching support and have dropped in some limited ARRAY Caching support.  Works ok, but given how arrays are normally used, there's unlikely to be a universal benefits.    

       I think we're pretty close to a release with this version,  there's still a few ideas floating around in my head for helper commands though.   Mainly just stuff to perform batched queries really.   Like reading the bounding volume (rect) from a sprite.   Which can then be drawn over a map level for selective refreshing styled render loops.   Just little things really.


 Download

       Old file removed

ATLUS

#35
something wrong with my tetris code. (PlayBASIC V1.64N2  Beta #12d)

http://www.underwaredesign.com/forums/index.php?topic=3832.0

kevin


I don't think it's beta 12 related, as it doesn't work in 11 either..

ATLUS

#37
i don't test code in 11 =)

OldNESJunkie


kevin

#39
  PlayBASIC V1.64N2  Beta #13a - Wrapping it up

       Was looking over the map library thinking about implementing some sprite to map masking function(s), but you can do much the same thing already.   I've added one new command though GetSpriteRect() which is a function to pull the bounding volume from a sprite after rotation and scaling.   Previously you'd have to query each vertex and then workout the rect from the vertex.   This can be very useful if you want to selectively refresh the backdrop, reducing the cost per pixel.  

       Selective refreshing in video games isn't a new concept,  it dates back to the dawn of game programming really.  8/16bit systems are notoriously slow, most weren't even quick enough to refresh a full frame of bitmap graphics at a playable rate, in particular when the scene contains overdraw.   You'd think that modern machines would be fast enough, but far from it.     Conceptually all we're trying to do, it minimize the number of the times each pixel that gets displayed is actually being drawn.   Pixels that are drawn over more than once,  are  costing us runtime performance.    

        If we imagine the standard FX buffer based refresh loop.  We'd have a FX formatted image the size of the display area, and we're making a Space Invaders game,  then the loop probably Clears the full screen buffer,  moves the aliens then renders them to the fx buffer.  If the screen is 800*600 and each alien is 32*32 pixels and there's say 100 of them on screen.    We can work out that to draw each frame we're hitting buffer around (800*600)+(32*32*100) =   480000 +102400 = 582400 times.

         Now clearly  that's a lot of fixed overhead, given much of the backdrop is going to be blank.    So a better approach would be to remember the area where each alien was being draw over, then to blank this area prior to be next frame redraw, avoiding the full screen CLS.   This reduces the redraw cost down to  (32*32*100) * 2 = (102400 *2) = 204800 times, cutting the cost per refresh in half.    
         
         Such a method would work fines, bit if aliens are being drawn over each other, then we're clearing / redrawing sectors of the original frame potentially more than one.    One easy way around this,  is to tag the character positions to refresh map.  The map is just a grid of blocks that need to be redrawn then. So it doesn't matter if the sprites over lap, we're only refresh that area once.    This is basically the approach the example bellow uses.  
               
        The following example creates a scene with moving sprite 'blob' things (Press Space to create), it's actually a variation of an older demo, the main change is that this version uses PB map/Level functions.    

        The code requires Beta 13 to run 100% correctly,  since older versions have a clipping bug CopyLevel, so it doesn't quite work in those versions.  

PlayBASIC Code: [Select]
;*=-----------------------------------------------------------------------------=*   
;
; >> Selective Map Update II (Dirty) Tile Map Refresh <<
;
; By Kevin Picone
;
; Built Using PlayBasic V1.64n2.
;
; Copyright 2012 by Kevin Picone All Rights Reserved.
;
;*=-----------------------------------------------------------------------------=*
; www.PlayBasic.com - www.UnderwareDesign.com
;*=-----------------------------------------------------------------------------=*

loadfont "arial",1,16,0,8


// -----------------------------------------------------------
// Size the Map blocks we'll use.
// -----------------------------------------------------------
constant TileWidth =32
constant TileHeight =32

// -----------------------------------------------------------
// Make the Backdrop image. This buffer is also used for the 'FX surface'
// -----------------------------------------------------------
BackDropFX =MakeBackdropImage()


// -----------------------------------------------------------
// Make a blob image to represent the sprites in the scene
// -----------------------------------------------------------
Blob= MakeBlobImage(64,64)

// -----------------------------------------------------------
// Define a type to simulate some characters in the scene.
// -----------------------------------------------------------
Type tAlien
Img
X#
Y#
speed#
direction#
EndType

// ------------------------------------------------------
// Dim a list called Character to hold the objects
// ------------------------------------------------------
Dim Character as TAlien list


// ------------------------------------------------------
// Set the clip zone of the object
// ------------------------------------------------------
clipSize=64
ViewportX1=-clipSize
ViewportX2=GetSCreenWidth()+clipSize
ViewportY1=-clipSize
ViewportY2=GetSCreenHeight()+clipSize


// ------------------------------------------------------
// MAKE MAP / LEVEL / BLOCKS from our backdrop picture
// ------------------------------------------------------

Map=NewMap(10)

ThisIMage=BackDropFX
IMageWidth =GetIMageWidth(ThisIMage)
IMageHeight =GetIMageHeight(ThisIMage)

TilesWide =IMageWidth/TileWidth
TilesHigh =IMageHeight/TileHeight

if (TilesWide*TileWidth)>ImageWidth then TilesWide++
if (TilesHigh*TileHeight)>ImageHieght then TilesHigh++

BlockCount=(TilesWide*TilesHigh)+1

CreateMapGfx Map,TileWidth,TileHeight,BlockCount,rgb(0,0,0),2

OriginalLevel=NewLevel(Map,TilesWide-1,TilesHigh-1)

rendertoimage ThisImage

// ----------------------------------
// Build map representation of this image
// ----------------------------------
Index=1
For ylp=0 to TilesHigh-1
For xlp=0 to TilesWide-1
Xpos=xlp*TileWidth
Ypos=ylp*TileHeight
GetMapblk Map,Index,Xpos,Ypos
PokeLEvelTile Map,OriginalLevel, Xlp,ylp,Index
Index++
next
next


RefreshLevel =NewLevel(Map,TilesWide-1,TilesHigh-1)

pastelevel map,OriginalLevel,Map,RefreshLevel,0,0,0

LevelTransparent Map,RefreshLevel,0


Screen=NewIMage(GetScreenWidth(),GetScreenHeight(),2)

;*=-----------------------------------------------------------------------------=*
; >> Main Loop <<
;*=-----------------------------------------------------------------------------=*
Do

// Add new charcter to scene if the space key is being pressed
if Spacekey()
Character = New tAlien
Character.img =Blob
Character.x =rnd(GetScreenWidth())
Character.Y =rnd(GetScreenHeight())
Character.Speed =rndrange(1,5)
Character.direction# =rnd(360)
endif


// Process and render to the objects in the character list
RenderToImage Screen


; lockbuffer
drawmap Map,RefreshLevel,0,0
; unlockbuffer

; reset the mask level
ClearLevel Map,RefreshLevel,0

lockbuffer

For each Character()

Speed#=Character.speed#
Angle#=Character.direction#
x#=Character.x+Cosradius(angle#,speed#)
y#=Character.Y+Sinradius(angle#,speed#)

if pointinbox(x#,y#,ViewportX1,ViewportY1,ViewportX2,ViewportY2)=false
Character=null
continue
Login required to view complete source code





PlayBASIC V1.64N2  Beta #13a - Download

Get PlayBASIC V1.64N2 BETA #13a (Retail Compiler Only Beta) (login required)  (Updated)




ATLUS

after i run my code, in root my disk D: created file "ByteCode.VM2". it's normal?

kevin


  normal in my version.. Refreshed the package since it was missing language files also.   

kevin


PlayBASIC V1.64N2 BETA #15 (Release Candidate)

      PlayBASIC V1.64 N2  Beta #15,  this revision fixes the outstanding known bugs listed in the bug forum.    I'm expecting this to be this the release version.    Therefore,  users are strongly advised to test this version across as many of their projects as possible prior to the release!



Download


     Get  PlayBASIC V1.64 N2 Beta #15 (login required)



ATLUS


kevin

#44
  PlayBASIC V1.64N2  Beta #15b - Docs Are Fun

    As with all upgrade phases, there's the unavoidable doc phase.   Dropped a couple of afternoons in already,  mainly just picking through where pictures could benefit.  Got a few ideas, but have only really made some for the mapping tutorial at this point.    

    Found one issue in beta 15 where mixing array caching with types in an expression could break the runtime.  So if you have an expression  like,

    SomeArray(Index)= SomeArray(Index) + SomeTYpedArray.Field

    It'd happily die.   Turns out the runtime shares some data between normal and typed arrays, making it untenable.  Since the parser caches the SomeArray(index) access before SomeTypedArray access, the location would be corrupted.   It's fixed in beta 15B,  but if you find a program that dies, then may well be a cause

     If you find one, try rearranging the expression like so

       SomeArray(Index)=  SomeTYpedArray.Field +SomeArray(Index)