Author Topic: Direct Pixel Drawing using kernel32, again [BB2D]  (Read 14273 times)

0 Members and 1 Guest are viewing this topic.

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
ok guys, again: im trying to get all the speed possible, but only in software mode (no WritePixel(Fast))!
i thought it could be useful for everyone, if there'd be a stable (and sometimes faster) software version of this, especially for demos or stuff. can you help me getting the code even faster?

Code: [Select]
;.lib "kernel32.dll"
;apiRtlMoveMemory(Destination*,Source,Length):"RtlMoveMemory"
;apiRtlMoveMemory2(Destination,Source*,Length):"RtlMoveMemory"

Const ScreenWidth=320
Const ScreenHeight=240
Graphics ScreenWidth,ScreenHeight,32,2
SetBuffer BackBuffer()

Global VideoBank=CreateBank(ScreenWidth*ScreenHeight*4) ;create virtual buffer in 32 bit(4 bytes per pixel)
BufferInfo=CreateBank(32) ;store buffer information here
LockBuffer()
 apiRtlMoveMemory BufferInfo,GraphicsBuffer()+72,32
 size=PeekInt(BufferInfo,20) * PeekInt(BufferInfo,24) * PeekInt(BufferInfo,28)/8 ;global size of buffer in bytes
 offset=PeekInt(BufferInfo,0) ;?not sure? - i think its the offset of the buffer in the RAM
UnlockBuffer()
If BankSize(VideoBank)<size Then RuntimeError "Could not create buffer"

Repeat
 col=Rand($000000,$FFFFFF)
 For currentpos=0 To size Step 4 ;<- this is the drawing loop, which fills the screen!
  PokeInt VideoBank,currentpos,col ;draw to virtual buffer
 Next
 ;Pixel(MouseX(),MouseY()) ;mousecursor

 apiRtlMoveMemory2 offset,VideoBank,size ;copy virtual buffer to graphics buffer
 Color 255,0,0
 Text 10,10,GetFPS()
 Flip 0
Until KeyHit(1)
End

Global FPS,FPSFrame,FPSTime ;stolen from ashadow ;)
Function GetFPS(ms=1000)
ctime=MilliSecs()
FPSFrame=FPSFrame+1
If ctime-FPSTime>ms
 FPS=FPSFrame*1000/ms
 FPSFrame=0
 FPSTime=ctime
EndIf
Return FPS
End Function

Function Pixel(x=-1,y=-1,hexcol=$000000)
If x>-1 And x<ScreenWidth And y>-1 And y<ScreenHeight Then PokeInt VideoBank,(y*(ScreenWidth)*4)+(x*4),hexcol
End Function

PS: look for the drawing loop, i noticed some strange things in there:
1. it seems that adding a random drawing color increases speed
2. for-next-loops are the fastest. normally, while-wend should be the fastest, but its the slowest and repeat-until is ranked 2nd

PS2: having a good processor/fast ram increases speed very strong: i got ~250fps on my sempron 3000+ and about ~920fps on a athlon 3200+. what fps do you have? also, Devils Child has even more fps with writepixelfast, which is always slower on my PCs

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #1 on: December 07, 2007 »
You haven't really posted anything for us to test.  Can you post source+exe and the results from your machine, then we can compare notes?

Jim
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #2 on: December 07, 2007 »
ok, here you go... seems to be to large for DBF-webspace, so i've uploaded it to my own webspace: http://www.dev-ch.de/upload/files/DrFreak339/direct_pixel.rar

EDIT: be sure to have a .decls for kernel32.dll with the lines:
Code: [Select]
.lib "kernel32.dll"
apiRtlMoveMemory(Destination*,Source,Length):"RtlMoveMemory"
apiRtlMoveMemory2(Destination,Source*,Length):"RtlMoveMemory"
« Last Edit: December 07, 2007 by DrFreak339 »

Offline Paul

  • Pentium
  • *****
  • Posts: 1490
  • Karma: 47
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #3 on: December 07, 2007 »
1680-1780 fps
Using ordinary writepixelfast gives me 1000 fps.
Ran it from my temp folder and it crashed.
The Exe works from the desktop though but crashes when I close it either with escape or the cross.
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #4 on: December 07, 2007 »
wow.. so much fps! didnt think of something like this!
ok, to the errors: cant run from temp: probably(!) a bug in blitz, where it cant load the decls/cant find the dll?
2nd bug: perhaps windows wants his memory back or something. i dont know, how internal blitz routines work. probably the "copy to virtual buffer" copies also somewhere else... this seems really bad, i have no idea how i could fix this...

btw: i think blitz finds all .dll's either defined with a decls(mostly in the same folder) or in the system32 dir, so "temp=???" brings an error...

Offline Paul

  • Pentium
  • *****
  • Posts: 1490
  • Karma: 47
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #5 on: December 07, 2007 »
wow.. so much fps! didnt think of something like this!
hehe, I've got a 8800 gts and a core 2 duo @ 3.7 ghz :P

After some more testing I've noticed that it doesn't always crash when closing, but usually.
If it helps I'm running windows vista 32bit
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #6 on: December 07, 2007 »
vista.. well, i cant test it.. also, none of my friends has it. they all have XP and they can run it without problems, but i think this could be it.
also i should mention: its theoretically not important, what card you have, because its winXP(and older)-software-drawing-stuff; only vista uses hardware to accelerate. i think you just have 1. fast ram and 2. a fast transfer from the cpu to the ram. i am really sure, expensive cards dont change this, because the PC from me, where its running with about 900 fps has a really cheap X600SE and on the pc with 200 fps i have a X1300 Pro(its about double the size of the x600 ;) )

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #7 on: December 08, 2007 »
About 900fps here on my Vista/Core2/8600GT.  Sadly I don't have BlitzMax so I can do any tests.  It crashes on exit.
I'm guessing the data structure located at GraphicsBuffer() isn't well defined?
Also, the video pointer is likely to point to a DirectDraw or Direct3D surface.  Usually that's supposed to be locked before you write to it - perhaps adding Lockbuffer()/Unlockbuffer() around the memcpy (rtlMoveMemory) will make it more reliable?

Jim
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #8 on: December 08, 2007 »
hmm.. i expected more on a double core machine. anyways: i did some tests concerning buffer handles: locking the buffers takes(!) about 20% of the speed and changing the offset of the pointer doesnt work. i have to access the buffer like this i think.

oh and: this isnt Bmax  ;) its 2D, but you need access to kernel32.dll functions

EDIT: i just noticed that drawing directly to the frontbuffer instead to the backbuffer gives about 6% more speed and it stops flickering (in wondowed mode)
« Last Edit: December 08, 2007 by DrFreak339 »

Offline Paul

  • Pentium
  • *****
  • Posts: 1490
  • Karma: 47
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #9 on: December 08, 2007 »
For me, locking the buffer before apiRtlMoveMemory2 and unlocking it just after takes about 40 fps.
locking it before all the pokes actually takes about 400 fps off. Are the pokes slower when the backbuffer is locked?
anyway, it still crashed when locking the buffer :(
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #10 on: December 09, 2007 »
Somehow my FSB multiplier had got reset to 6X instead of 10X and my CPU was running at 1.6 instead of 2.66! I now get about 1380.  If it's B2D I might have an experiment on an XP machine round here (B2D editor is too broken to use on Vista IIRC).  If the underlying memory is allocated by DirectX, then you definitely need to lock/unlock it.  But what exactly goes on inside Lockbuffer/Unlockbuffer might not be what you want it to do.
The locks are important because they control who has access to the memory - when you lock it, the gfx chip can't use it, and vice versa, which is another possible reason for the apparent speed loss - right now both you and the video chip are concurrently accessing the ram.  Another (more remote) possibility is that the buffer can move between unlock and lock, and the memory pointer can change.  That's most likely to happen after an Alt-Tab or Ctrl-Alt-Del brings up a system menu.

I suspect it's crashing because some memory write or other is overwriting something it shouldn't.  Won't be that hard to find out what...

Jim
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #11 on: December 11, 2007 »
ok, looks like, you have to free the buffer (in vista only?), before you exit the program or else it will crash, am i understanding this right? anyways, i have no idea, how to do this. im going to search the kernel32.dll. there has to be a function to free the memory to avoid crashes

Offline Paul

  • Pentium
  • *****
  • Posts: 1490
  • Karma: 47
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #12 on: December 11, 2007 »
Jim, the cpu multiplier gets set to 6x on new intel(don't know about old or amd) cpus when they don't think the're under load. this is done to keep them cool and is normal.

OT:
you could try reading the memory position of the backbuffer every frame in case it moves the buffer.
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #13 on: December 11, 2007 »
->DrFreak339 - you definitely do not want to be trying to free that memory!  What I am saying is that for whatever reason, the memory you *think* you are able to write over with apiRtlMoveMemory is actually not entirely available for you to write over, or is not available at the times you're assuming it's available.  On XP you're trashing something unimportant and getting away with it.  On Vista you are trashing something important and it is crashing.
It's definitely worth checking up on what Paul said about the framebuffer moving.

->Paul - Yeah, I guess power management would do that, but it should clock back up to 10 under demand and it didn't.  I had to reset it in the BIOS!

Jim
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #14 on: December 18, 2007 »
ok, heres the update. its just a little change: im getting the buffer information(-> RAM offset) new in each main-loop.
vista users please test.

Code: [Select]
;.lib "kernel32.dll"
;apiRtlMoveMemory(Destination*,Source,Length):"RtlMoveMemory"
;apiRtlMoveMemory2(Destination,Source*,Length):"RtlMoveMemory"
Const ScreenWidth=320
Const ScreenHeight=240
Graphics ScreenWidth,ScreenHeight,32,2
SetBuffer BackBuffer()

Global VideoBank=CreateBank(ScreenWidth*ScreenHeight*4) ;create virtual buffer in 32 bit(4 bytes per pixel)

Repeat
 BufferInfo=CreateBank(32) ;store buffer information here
 LockBuffer()
  apiRtlMoveMemory BufferInfo,GraphicsBuffer()+72,32
  size=PeekInt(BufferInfo,20)*PeekInt(BufferInfo,24)*PeekInt(BufferInfo,28)/8
  offset=PeekInt(BufferInfo,0)
 UnlockBuffer()
 If BankSize(VideoBank)<size Then RuntimeError "Could not init buffer"
 FreeBank BufferInfo

 col=Rand($000000,$FFFFFF)
 For currentpos=0 To size Step 4
  PokeInt VideoBank,currentpos,col ;draw to virtual buffer
 Next

 apiRtlMoveMemory2 offset,VideoBank,size ;copy virtual buffer to graphics buffer
 Color 255,0,0
 Text 10,10,GetFPS()
 Flip 0
Until KeyHit(1)
End

Global FPS,FPSFrame,FPSTime
Function GetFPS(ms=1000)
ctime=MilliSecs()
FPSFrame=FPSFrame+1
If ctime-FPSTime>ms
 FPS=FPSFrame*1000/ms
 FPSFrame=0
 FPSTime=ctime
EndIf
Return FPS
End Function

Function Pixel(x=-1,y=-1,hexcol=$000000)
If x>-1 And x<ScreenWidth And y>-1 And y<ScreenHeight Then PokeInt VideoBank,(y*(ScreenWidth)*4)+(x*4),hexcol
End Function

EDIT: slowdown of ~15-20%, but if it works for vista users... its probably worth it
« Last Edit: December 22, 2007 by DrFreak339 »

Offline Paul

  • Pentium
  • *****
  • Posts: 1490
  • Karma: 47
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #15 on: December 25, 2007 »
sry, same problem :(
what the heck is vista doing?
or is it just xp not noticing?
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #16 on: December 25, 2007 »
Can you try changing
Code: [Select]
For currentpos=0 To size Step 4
  PokeInt VideoBank,currentpos,col ;draw to virtual buffer
 Next
to
Code: [Select]
For currentpos=0 To size-4 Step 4
  PokeInt VideoBank,currentpos,col ;draw to virtual buffer
 Next
and reposting the exe?  I think it's writing one too many pixels to the screen.

Cheers.

Jim
Challenge Trophies Won:

Offline Paul

  • Pentium
  • *****
  • Posts: 1490
  • Karma: 47
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #17 on: December 26, 2007 »
Thats great Jim, it worked :)
ran it more than ten times in a row without crashing :D
Checking where the buffer is each frame does not seem to be necessary at all.
At 1680 i get 80 fps with this and 17 with writepixelfast, both in non debug.

Great work both of you!
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Offline a

  • ZX 81
  • *
  • Posts: 21
  • Karma: 0
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #18 on: December 26, 2007 »
ok, paul, just saw your post after uploading the new exe, so here you can have it anyways^^: http://www.dev-ch.de/upload/files/DrFreak339/poke_pixel_vista.rar

changes: 1. the offset in the ram is requested in each main loop
2. size is substracted by 4 (yep, i should have thought about this before^^)
it should work bugfree on each system now!

oh and paul: i think its XP not noticing. doesnt vista has this new "security features", which XP doesnt has?

and here is the source (forgot to include into the archive, sorry):
Code: [Select]
;.lib "kernel32.dll"
;apiRtlMoveMemory(Destination*,Source,Length):"RtlMoveMemory"
;apiRtlMoveMemory2(Destination,Source*,Length):"RtlMoveMemory"
Const ScreenWidth=320
Const ScreenHeight=240
Graphics ScreenWidth,ScreenHeight,32,2
SetBuffer BackBuffer()

Global VideoBank=CreateBank(ScreenWidth*ScreenHeight*4) ;create virtual buffer in 32 bit(4 bytes per pixel)

Repeat
 BufferInfo=CreateBank(32) ;store buffer information here
 LockBuffer()
  api_RtlMoveMemory BufferInfo,GraphicsBuffer()+72,32
  size=PeekInt(BufferInfo,20)*PeekInt(BufferInfo,24)*PeekInt(BufferInfo,28)/8
  offset=PeekInt(BufferInfo,0)
 UnlockBuffer()
 If BankSize(VideoBank)<size Then RuntimeError "Could not initialise buffer."+Chr(13)+"Program will quit."
 FreeBank BufferInfo

 col=Rand($000000,$FFFFFF)
 For currentpos=0 To size-4 Step 4 ;yes, thanx jim ;)
  PokeInt VideoBank,currentpos,col ;draw to virtual buffer
 Next

 api_RtlMoveMemory2 offset,VideoBank,size ;copy virtual buffer to graphics buffer
 Color 255,0,0
 Text 10,10,GetFPS()
 Flip 0
Until KeyHit(1)
End

Global FPS,FPSFrame,FPSTime
Function GetFPS(ms=1000)
ctime=MilliSecs()
FPSFrame=FPSFrame+1
If ctime-FPSTime>ms
 FPS=FPSFrame*1000/ms
 FPSFrame=0
 FPSTime=ctime
EndIf
Return FPS
End Function

Function Pixel(x,y,hexcol=$000000)
If x>-1 And x<ScreenWidth And y>-1 And y<ScreenHeight
 PokeInt VideoBank,(y*(ScreenWidth)*4)+(x*4),hexcol
EndIf
End Function

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Direct Pixel Drawing using kernel32, again [BB2D]
« Reply #19 on: December 26, 2007 »
Thanks for the EXE, I can confirm it works for me too. ;D  Just over 1030fps.

You have to bear in mind that if you overwrite memory you don't own, anything could happen, including no ill effects.  It runs on your XP box because your particular layout of memory/driver/gfx card don't rely on that value.  It's quite possible that another XP box with a different driver could blow up too.  Add to that, that Vista video drivers are total re-writes and the chances of overwriting something important are quite high!  I don't think it's anything to do with Vista's extra security features at all - that's not really how they work.

Jim
Challenge Trophies Won: