News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

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

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

Previous topic - Next topic

kevin

#105
 PlayBASIC V1.64N3 - Beta 9d - Working Threading ?

     After a day of banging my head on the keyboard I think we've got this working at a useful state.   The idea of adding this to the blitx fx functions is we can set up a parallel rendering/processing situation.  Where a secondary thread is doing a the FX screen copy on second cpu core, while our main program is doing something else.


 Current Commands (WIP)

      BlitFXThreadMode State         (1= Threading on,  0 = Threading Off immediate mode rendering)

      GetBlitFXThreadMode()       ; Get the current thread mode


      BlitFXThreadPriority  ThreadPriority    ;  Set the priority of this threading request.  Range between 1 to 15.   1 being lowest, 15 being highest (critical)

   ThreadPriority=GetBlitFXThreadPriority()   ; Get the current thread OS level thread priority that threaded rendering is using.  


   WaitOnBlitFX()           ; This thread waits until our drawing process is complete.  



 How Not To Use Threading

     Threading is only of any value, if you design your program to perform the task required in parallel with the main program.   Linear thinking and threading don't mix.

     For example , If I enable threading and call a blitfx function say BlitImageClear,  then this task is going to be offloaded from the primary program onto a second CPU core.  See bellow,

PlayBASIC Code: [Select]
      ; start the blitting the from buffer to the PB screen
rendertoscreen


; When thread mode is enabled, this BlitFX function will be pushed onto a
; second thread.

BlitIMageClear Screens(FrontBuffer),0,0,$304050

; wait until the other thread completes it;s task..
WaitOnBlitFX()






    Here we see a program that's gaining nothing from threading at all, why ?  The reason for this, is the the main program is being forced to sit and wait until the secondary rendering thread completes it's task.     What we should be doing, is getting the main program to perform some other no related task while the rendering takes place in the background.  And only wait for the blitx fx to complete when we actually need to use the result of that rendering.    

    In the main example bellow, we're starting the second thread doing the BlitImageClear, then rather than waiting for it complete, we're rendering our batch of circles to a secondary FX screen.    In a dual/quad core system the two tasks are being performed in unison.   Generally the blitFX function will finish long before main program is done drawing  the batch of circles, so we're not really gain much, other than offloading one screen copy onto the second core.




Download

    obsolette file removed

 

Threading Example

   Here's today update of the circles demo.   This time we're using the BlitImageAlphaPostMultColour function to copy the screen.   This function Copies the pixel then multiples the source pixel with the colour of your choice.   Standard depreciation effect.

   Function Keys = Number of Circles
   Esc               = Exit Demo
   D                  = Display Info
   M                  = MMX state
   Space             =Toggle Threading
   Left/Right Arrow = Change Thread Priority   (1 to 15)    


PlayBASIC Code: [Select]
   #include "BlitIMage"

makebitmapfont 1,-1,8
OptExpressions 3

Type tCircle
x#,y#
SpeedX#
Size
Colour
EndType

Dim Object as tcircle list


CircleCount=500
SpawnCircles(CircleCount)

Dim Screens(1)

; CReate two FX buffers. We'll be doubling buffer the rendering
Screens(0)=NewImage(800,600,2)
Screens(1)=NewImage(800,600,2)


FrontBUffer =0
BackBUffer =1-FrontBuffer

renderscene=1

; Enable Threading on BlitFX functions (At this point only BlitIMageClear is supported)
BlitFXThreadMode 1



do

; start the blitting the from buffer to the PB screen
rendertoscreen


; When thread mode is enabled, this BlitFX function will be push onto a
; second thread. When it's turned off, the main cpu renders this here
; and now.


; BlitIMageClear Screens(FrontBuffer),0,0,$304050
BlitImageAlphaPostMultColour(Screens(FrontBuffer),0,0,$e0a090)


; While the back ground thread is working drawing the Front Buffer image to
; the PB screen, we start drawing on to our backbuffer screen image.
; Meaning it's doing two things at once, we're drawing circles, while
; a second core is doing the BlitIMageClear'ing

rendertoimage Screens(BackBuffer)

if renderScene
Inkmode 1+64
For each Object()
x#=Object.x+Object.SpeedX#
circlec x#,Object.y,Object.Size,true,Object.Colour

if x#>1600 then x#=-800
Object.x=x#
next
inkmode 1
endif


if scancode()<>0

for lp=1 to 10
if FunctionKeys(lp)
CircleCount=lp*500
SpawnCircles(CircleCount)
endif
next


if Leftkey()
Count=GetBlitFXThreadPriority()-1
if Count>0
BlitFXThreadPriority Count
endif
endif

if Rightkey()
Count=GetBlitFXThreadPriority()+1
if Count<16
BlitFXThreadPriority Count
endif
endif

; Press Space to toggle Threading
if Spacekey()
BlitFXThreadMode 1-GetBlitFXThreadMode()
flushkeys
endif

; M = MMX toggle
if Keystate(50)
gfxmmx 1-Getgfxmmx()
flushkeys
endif

; R = Render scene
if Keystate(19)
renderscene=1-renderscene
flushkeys
endif

; D toggle the extra text details
if Keystate(32)
Details=1-details
flushkeys
endif

endif


; Check if threaded blitting is enabled ?
if GetBlitFXThreadMode()
WaitTime=Timer()
; if it is, wait for the blit to complete
WaitOnBlitFX()
WaitTIme =timer()-WaitTIme
endif


Setcursor 0,0

lockbuffer
print "Threading:"+Str$(GetBlitFXThreadMode())
print "Thread Priority:"+str$(GetBlitFXThreadPriority())
print "Fps:"+str$(Fps())
print "Status:"+Str$(GetBlitFXStatus())
print "Wait Time:"+str$(WaitTIme)
print "Object Count:"+str$(CircleCount)
if Details=1

print "MMX:"+str$(GetGFXmmx())

print FrontBuffer
print BackBuffer

for lp =0 to 50
v=QueryAsync(lp)
if V
Login required to view complete source code



ATLUS


kevin


PlayBASIC V1.64N3 - Beta 9e - Welcome to threading

      This version now supports a couple of different blitx FX rendering calls for those really adventurous PlayBASIC programmers out there.   The current system is singular job based solution.   Once all the fillers are converted, we'll look at adding stack/cache based creation also, perhaps even swarming mode, which will make it easier for those unable to wrap their minds around parallel programming.     However, that will no doubt mean some command names/parameter change etc.  So I'm not going to bother adding them to the doc's for this upgrade.    Will do that once the implementation has settled. 




Download

  Get Latest Beta (login required)




kevin

 PlayBASIC V1.64N3 - Beta 9e - Blit Modes & Threading

   Today was the day i'd penciled in as release day,  but time has slipped by once again.   Currently about 1/2 way through making the blit fx functions threading safe.   It's a lot more code than you might think, those 5 or 6 functions are around 380K of  C/Assembly.    Making them thread safe just means going through and converting all the function interfaces to use local structures rather than global stuff.    Most of them are turning out to be easy, but as always, it's then you run into something that just refuses to work.   Which has been the story of this session.   While updating the Alpha Colour Addition  fillers, it turned out the 15bit version just didn't work.   It didn't crash, but the resulting image wasn't what i was expecting.   Given that it's pretty unusual format today, could have thrown it, was tempted after a while, but ended up rewriting it completely.  Works now and seems a tad quicker.

  I'm pretty tempted to add some image processing stuff and batching functions also.     You can currently light map a 2d game by using the BlitImageAlphaMultImage function.  This function takes two images and multiplies the RGB channels of every pixel together, writing out the resulting pixels.    So one image is the unlit picture/game/demo effect and those is light map.     If you've ever bothered to look through the example pack,  there's a few demos showing it's usage, or in Spooky Shadows.     Drawing the scene and light maps is fairly;y straight forward, but heavy in terms of rendering performance.  

  Threading should make effects like this a cake walk.    Basically the clever programmer would split the rendering process in half.   The main programs draws the game scene as normal,  but the lighting stuff is pushed off onto a thread.   So basically while we draw the game stuff, it's drawing the lighting stuff.    If we can queue up render items,  this should make drawing light maps virtually free on multi-core systems..

  The mind boggles.  :)


kevin


PlayBASIC V1.64N3 - Beta 10

      This beta rounds out the threading support for the BlitImage functions, so all the main functions can now be execute in the background.  We need users to test this as much as possible.  That doesn't mean running some example and saying yeah it works, that means writing your own examples.   You'll need to, if you want your games to support multi core systems.   

      To push a render task onto the secondary thread, just enable threading.. call the render function as normal.   When threading is ON (set to 1), the draw request is pushed from the main program to a second thread, which will start immediately in the background.   Some caution is needed, as we can't reliably draw to the same surface that the thread function is drawing to.   Because,  both our program thread and the background thread are running together.   If the background clears the screen say, while you draw a sprite to the same surface,  sometimes you'll see  a cleared background with a sprite in front, other times you'll see no sprite..  The latter could occur because we've not waited for the background to complete it's work.  So to get the best results you're going to have to structure your program accordingly 



Download

  Get Latest Beta (login required)




kevin

#110
  PlayBASIC V1.64N3 - Beta 11  - Cross Fading Images

      One of the things that I only just noticed that's missing from the BlitImage library of functions, was a variable alpha blending function.  Normally if you wanted to cross fade between two surfaces.   You'd alpha blend surface B onto A, then drawn A to the screen.   Which will work, but it's a destructive process.    There are times where you would want to draw a pair blended surfaces without altering them.

      The picture bellow is from a mutated version of the demo source (form an earlier post in this thread) where it's drawing a bunch of alpha additive circles to the buffer, depreciating the entire buffer using the Alpha Multiplication, which creates the blurring.   This  scene represents one surface, which is then being cross faded with a picture (just some old WIP piccy).   On my system (7 years old) the cross fade (with MMX enabled, single threaded) is about a 4 millisecond effect.    Newer systems will chew through much quicker.  But the point is that this process can be threaded.    So even it took 4 milliseconds on a dual core system, the job can pushed off onto the second core.  If the task can be interleaved behind other operations in our program,  it's becomes a free effect at runtime.

      The last few days i've been focusing entirely on the blit image functions.  Found a few well hidden issues in some fillers and have made a number tweaks. Since this is basically a rendering library,  it's about 50% assembly.    There's MMX versions of most of the fillers, but not all.  It's well worth adding, as they're generally twice as quick, but everything needs legacy fall back routines, making the process of adding a 'method' slow going.    The new alpha blender function (which only supports 32bit, 16bit + 15bit pixel formats) is actually 6 routines.  Don't think i'll bother a 24bit version, since none of the other blitimage functions seem to support it.  


 Swarming

       When threading was last on the radar, the approach was entirely based around using a swarm of threads spread across the host system to perform common tasks in unison. This allows the program to use as may threads as the programmer wants (within reason), meaning a computer problem can be broken up into small jobs and distributed across many CPU's at once.   Today we don't have this, the new implementation is queue based.  Where we push a job from our main program onto a secondary thread.    All these jobs run on a separate core to main program (if you have multi core system), but only on the one core.   There's advantages and disadvantages to both.

        Anyway you can share rendering of  blitImage functions between two cores, by first setting the Viewport of the destination surface, then call the render function.   This will push the job off to core #2,  core #1 will continue on.  Where we'd set the viewport to the other half of the screen and then call the same blit image function we wanted again.     So we're doing is splitting the job between the two cores.    So core 2 is drawing the top half of the screen and core 1 the bottom.      

     
PlayBASIC Code: [Select]
   #include "blitimage"




Screen=NewImage(800,600,2)


Do

rendertoimage Screen
inkmode 1+64
circlec mousex(),mousey(),50,true, $304050

inkmode 1


rendertoscreen

; this first request is pushed onto core #2
ScreenViewport 0,0,800,300
; turn blitimage threading on
BlitFXThreadMode ON

; Calling this function pushes the task off onto core #2
BlitImageAlphaPostMultColour(Screen,0,0,$e0a0b0)

; while Core#2 performs the blitimage function on the top half


; turn blitimage threading on
BlitFXThreadMode OFF

; we now change the viewport to the lower half.. So core #1
;will render this now
; this first request is pushed onto core #2
ScreenViewport 0,300,800,600
BlitImageAlphaPostMultColour(Screen,0,0,$e0a0b0)

; restore the viewport
ScreenViewport 0,0,800,600

; better wait for the core #2, it may not have complete it's job
WaitOnBlitFX()

Sync
loop






kevin

#111
Recursion And Self Modification Don't mix

    While 'testing'  beta 11,  thought i'd give the old chestnut of writing a limb based animation system quick try.   The concept is to create humanoid characters from set of linked limbs,  where the links act as joints.    While knocking a mock up together, ran into some of issues when rendering the limb set.  Since a set of limbs can link an unknown number of levels, using recursion (functions that call them selves) seems like an easy solution, and it is.    But wouldn't ya know it.. Ran the code, but only one list of limb appears.  

     Testing the loop and it theoretically works, so after putting on my detective hat,  It's here one of recent optimizations appears to come and bite us in the back side.    Modern revisions of V1.64N 2 and 3 use a self modification in certain looping structures (all 1.64 versions use some), these changes allow us to get rid of some dynamic fetching from the 'end' value in For/Next loops in particular.     This can cause issues with a for/next loop is inside a function that's calling itself from inside the loop.     While I think this situation is fixable without reverting back to the older implementation,  there does seem to be some iffy situations in regard to how recursive function sets up the new call.    

     Since writing the debugger a few months ago, back them it seem that the compiler was writing some bogus scope changing data for function calls.  Had a look and the code seems ok, but there's something not quite right with it somewhere..  Hopefully it's just some logic error, but tracking them down can be very frustrating, not too mention time consuming.  

     At the start of the week, my objective was to build the upgrade at the end of the week,  this is still the goal. Regardless so if the recursion issue can be ironed out in time or not.


  Test Code
         
PlayBASIC Code: [Select]
Function Search(LInk)
print "Begin Searching:"+Str$(LInk)
if (link<5) then Search(link+1)
print "End Searching:"+Str$(LInk)
EndFunction

Search(0)


sync
WaitNoKey
WaitKey





  Working in V1.64N3 Beta 12

PlayBASIC Code: [Select]
   Thing=0


Function Search(LInk)
b#=link*15
c#=b#
#break

print "Begin Searching:"+Str$(LInk)
print "prior to call:"+Str$(b#)
if (link<10)
Search(link+1)
endif

print "after call:"+Str$(b#)
print "End Searching:"+Str$(LInk)
EndFunction link


print Search(8)


sync
WaitNoKey
WaitKey







ignore, just a little test to see if if the scope table has all the expected locals in it.

PlayBASIC Code: [Select]
   zzz=45
global Dude
Dude=1222
Cool(11)
Cool(112)
dd=34
a=5



Function Cool(scale#)

zzz=123
local dude
dude=45
zz=45

a=zzz*45

global Sugar
sugar=12234


Dim Bill as byte pointer

aaa#++
aabb$="a"

EndFunction


print dude
Print sugar
print zzz

sync
WaitKey






kevin

#112
 PlayBASIC V1.64N3 - Beta 12a

      OK so with this beta we're well and truly at the pointy end of the process, in this version I've gone all out last night and replaced how the VM initializes and changes scopes completely.   These changes affect function calls in general, but mainly recursive function calls, which had a few gremlins in them.   The new solution uses less memory and is slightly quicker over 10,000 function calls.    There's still remains a few dramas which can occur when recursively calling a function within a for/next loop, as well when returning values inside the recursive function call.   The latter I believe is by product of how functions are implemented, so it may not be feasible to solve without making some major changes to the runtime tech.  

      Anyway,  we need you to run as much of your programs through this build as possible.   You shouldn't really notice any difference  



Download

 Get Latest Beta (login required)





VM1 Classic Function Benching

      Been testing the performance of V1.64N3 function calling against V1.64L  learning edition (only version on my desk top),  the test is calling 3 pairs of  functions with an identical psub  10,000 times each.    The results show just how much overhead Functions have compared to psubs.    Today's build of V1.63N3 Beta 12B includes a few optimizations in how values are returned from User defined functions, even with those  opt's removing one move instruction per function  call, there's not a huge difference in performance.    There's some, but nothing to write home about.   



     

   

kevin

#113
 PlayBASIC V1.64N3 - Beta 12b / 12c

     This revision focuses on fixing the known stack related recursion issues, therefore it's able to return data from inside a recursive calls.   It's also had any number of tweaks made to the stack operations to try and shave off even more execution cycles in function calls.    

      Download Bellow

kevin

#114
 PlayBASIC V1.64N3 - Beta 12d

      Yep another step towards insanity.  Shortly after posting beta 12c, noticed a few examples that didn't work with that revision.   Managing the stack when the functions allow multiple returns and recursion is something of a nightmare.   After another rethink, ended up splitting how the data is stored, in order to avoid the possible data collisions.  Which turns out makes the call that little bit faster also.

      Today's build seems happy to run recursive functions calls with or without input parameters or return parameters.


      I'm expecting this to be the release version (if no related issues are found) so get downloading and get testing


Download




kevin


Working ?

    So I take it beta 12D is working as normal for people (yeah.. all 3 of you, simply pathetic! ).  It's be at least good have some confirmation of it's status before releasing it.   Been doing some more doc's tidy stuff yesterday.  Added a few optional parameters here and there, like FindData default to forward mode. Stuff Like that.       


micky4fun

Hi all

sorry , yep seems fine here on my stuff ,  :)

mick :)

OldNESJunkie

Sorry Kevin,

Seems to work OK for me as well....

Sigtrygg

Hello Kevin!

Both versions of HellEagle (Map and Sprite)
work fine with Beta 12d.

Greetings

Sigtrygg

stevmjon

i program on the weekends, so i will test it then.

i would assume you would get more people downloading on weekends than during the week?

   stevmjon
It's easy to start a program, but harder to finish it...

I think that means i am getting old and get side tracked too easy.