In case you hadn't noticed from my previous 'ramblings', I'm a big fan of David's 'resource binder'. I like to think that distributing an executable which contains all it's 'static' data, instead of using external files is neat !
Quite some time ago, before David modified res.e to allow the use of bitmaps, I 'stole' a routine from win32lib, itself, which allowed me to do this.
When David finally added rReadBmp() , I wrote a version of this benchmark to compare the two methods.
It should be pointed out that 'benchmarking' under Windows is not particularly accurate, because Windows *is* a multi-tasking system, and may be doing things in the background, that will influence another programs 'run-time'. Also, if you have a newer-faster computer, you might have to increase the loopCount variable to get meaningful results.
This program basically creates a pair of bitmaps from a single resource file 2000 times, and discards all but the last pair, which it finally writes out to the screen. The program creates two different windows, the first displays the results using loadBmpResource(), and the second window uses rReadBmp() and createDIB().
--
testresource.exw
without type_check
include win32lib.ew
include res.e
-- the two bitmaps, in a real .res file, this time. ( testres.res )
rFile( "undercon.bmp" )
rFile( "underco2.bmp" )
integer loopCount
-- increase this, if you have a super-puter.
loopCount=2000
constant
MyWin = create( Window, "Test loadBmpResource", 0, 0, 0, 300, 100, 0 ),
Bitmap1 = create( Bitmap, "", MyWin, 5, 5, 40, 38, 0 ),
Bitmap2 = create( Bitmap, "", MyWin, 55, 5, 40, 38, 0 ),
Labely = create( LText, "", MyWin, 10, 50, 230, 20, 0 ),
MyWin2 = create( Window,
"Test rReadBmp/createDIB", 0, 0, 100, 300, 100, {WS_CAPTION} ),
Bitmap3 = create( Bitmap, "", MyWin2, 5, 5, 40, 38, 0 ),
Bitmap4 = create( Bitmap, "", MyWin2, 55, 5, 40, 38, 0 ),
Labelz = create( LText, "", MyWin2, 10, 50, 230, 20, 0 )
--pokes resource file to memory.
function pokeResource( sequence fileName, atom fSize )
atom image
integer hFile, byte
hFile = rOpen( fileName, "rb" )
image = allocate( fSize )
for i = 0 to fSize-1 do
byte = getc ( hFile )
poke( image+i, byte )
end for
close( hFile )
return image
end function
--slightly modified loadBitmapFromFile2()
--reads BMP from resource file to memory.
--you MUST specify the bitmap size !
function loadBmpResource( sequence fileName, atom fSize )
atom image, bmInfoHeader, bmBits, bmColors, hdc, hDib
image = pokeResource( fileName, fSize )
bmInfoHeader = image + SIZEOF_BITMAPFILEHEADER
bmBits = image + fetch( image, bfOffBits )
bmColors = bmInfoHeader + SIZEOF_BITMAPINFOHEADER
hdc = getDC( Screen )
hDib = w32Func( xCreateDIBitmap, {
hdc, address( bmInfoHeader, bmiHeader ),
CBM_INIT,
bmBits,
bmInfoHeader,
DIB_RGB_COLORS} )
releaseDC( Screen )
free( image )
return hDib
end function
atom ti, map, map2, map5, map6, jk
sequence map3, map4
procedure Start_up( integer self, integer event, sequence params )
setVisible( MyWin, 1 )
setVisible( MyWin2, 0 )
ti=time( )
for i= 1 to loopCount do
map=loadBmpResource( "undercon.bmp", 892 )
map2=loadBmpResource( "underco2.bmp", 892 )
if i < loopCount then
jk = w32Func( xDeleteObject, {map} )
jk = w32Func( xDeleteObject, {map2} )
end if
end for
setBitmap( Bitmap1, map )
setBitmap( Bitmap2, map2 )
repaintWindow( Bitmap1 )
repaintWindow( Bitmap2 )
setText( Labely,
"bitmaps drawn in " & sprintf( "%3.2f", time( )-ti ) & " seconds, " )
-- now show second window
setVisible( MyWin2, 1 )
ti=time( )
for i= 1 to loopCount do
map3=rReadBmp( "undercon.bmp" )
map4=rReadBmp( "underco2.bmp" )
map5=createDIB( map3 )
map6=createDIB( map4 )
if i < loopCount then
deleteObject( map5 )
deleteObject( map6 )
end if
end for
setBitmap( Bitmap3, map5 )
setBitmap( Bitmap4, map6 )
repaintWindow( Bitmap3 )
repaintWindow( Bitmap4 )
setText( Labelz,
"bitmaps drawn in " & sprintf( "%3.2f", time( )-ti ) & " seconds, " )
end procedure
procedure kill_objects( integer self, integer event, sequence params )
jk = w32Func( xDeleteObject, {map} )
jk = w32Func( xDeleteObject, {map2} )
end procedure
setHandler( MyWin, w32HOpen, routine_id( "Start_up" ) )
setHandler( MyWin, w32HDestroy, routine_id( "kill_objects" ) )
WinMain( MyWin, Normal )
--end--The main reason, of course, that the second block of code is so much slower, is that it converts the bitmap into a Euphoria ( DOS ) compatible sequence, which isn't really required in a Windows program.
--
I should point out that if you create a bitmap using createDIB(), you can destroy it with deleteObject().
You can't use this procedure with a
bitmap created using loadBmpResource().
You have to call the function xDeleteObject()
yourself, because win32lib will not destroy an object that it hasn't
created internally.
... and you *should*
, at least, destroy these objects on program exit, or they will STAY
in memory !
--
On a historical note: these demos run at
32 and 100 seconds on my ancient 486,
...and at 8 and 24 seconds
on a P166.
Benchmarking addendum !
Here's a little code snippet you can try at the beginning of any Windows 'benchmark' you write, which might improve the consistency of your tests. It basically just gives your program a higher priority, which usually defers any other program's ( background ) activity, until yours is finished. It's not recommended that you use this for normal programs as a whole.
--
without type_check
-- define requirements, constants, and 'hooks' to DLL and functions.
include dll.e
object process_id,class_priority,thread_id,thread_priority
constant
--NORMAL_PRIORITY_CLASS = 32,
HIGH_PRIORITY_CLASS = 128,
--THREAD_PRIORITY_NORMAL = 0,
THREAD_PRIORITY_TIME_CRITICAL = 15,
kern32=open_dll("kernel32.dll"),
current=define_c_func(kern32,"GetCurrentProcess",{},C_INT),
zSetPriorityClass=define_c_func( kern32,"SetPriorityClass",{C_INT,C_INT},C_INT),
zGetCurrentThread=define_c_func( kern32,"GetCurrentThread",{},C_INT),
zSetThreadPriority=define_c_func( kern32,"SetThreadPriority",{C_INT,C_INT},C_INT)
-- do it !
process_id=c_func(current,{})
class_priority=c_func(zSetPriorityClass,{process_id,HIGH_PRIORITY_CLASS})
thread_id=c_func(zGetCurrentThread,{})
thread_priority=c_func(zSetThreadPriority,{thread_id,THREAD_PRIORITY_TIME_CRITICAL})
--
...end...