Hardware Graphics Acceleration

Up to this point all graphics introduced in this tutorial have been controlled by the CPU and QB64's software graphics rendering routines. While impressively fast, software rendering has its limitations. QB64 offers the capability of using your graphics card's powerful GPU (Graphical Processing Unit) and video RAM to manipulate graphics on a hardware level massively increasing the performance of graphics on the screen.

A Demonstration

It's easy to underestimate the benefit that hardware rendering brings to QB64 as it's often an overlooked aspect of game programming utilizing QB64. The following demonstration highlights the massive increase in speed and power that hardware rendering brings to the table. The demonstration begins by creating 8000 individual sprite images and controls all of them on the screen in software rendering mode. On my computer system, a 6th generation i7, software rendering achieves around 20 frames per second. That's darn impressive given that all of these sprites are being updated by the CPU and QB64. However, pressing the 'H' key puts the program into hardware rendering mode and you won't believe ... well, run the program and see for yourself.

( This code can be found at .\tutorial\Lesson22\SWvsHW.bas )

OPTION _EXPLICIT '                declare those variables son!

CONST TOTAL = 8000 '              too many circles will crash program depending on amount of RAM and VRAM
CONST SWIDTH = 1280 '             screen width
CONST SHEIGHT = 720 '             screen height

TYPE SPRITEXY '                   sprite location and vector
    x AS SINGLE '                 horizontal coordinate
    y AS SINGLE '                 vertical coordinate
    xdir AS SINGLE '              x vector
    ydir AS SINGLE '              y vector
END TYPE

DIM SpriteSW(TOTAL) AS LONG '     software sprites
DIM SpriteHW(TOTAL) AS LONG '     hardware sprites
DIM SpriteXY(TOTAL) AS SPRITEXY ' sprite locations and vectors
DIM HWSprite AS LONG '            original sprite used for copying ('HARD' printed inside)
DIM SWSprite AS LONG '            original sprite used for copying ('SOFT' printed inside)
DIM c AS INTEGER '                sprite counter
DIM Software AS INTEGER '         -1 in software mode, 0 in hardware mode
DIM a AS STRING '                 key pressed by user
DIM t AS DOUBLE '                 timer at start of frame
DIM f AS INTEGER '                frame counter
DIM tf AS INTEGER '               total frames in one second

RANDOMIZE TIMER '                                                  seed random number generator
SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32) '                            create screen canvas
Software = -1 '                                                    start in software mode
HWSprite = _NEWIMAGE(50, 50, 32) '                                 temp hardware sprite image (notice 32)
SWSprite = _NEWIMAGE(50, 50, 32) '                                 temp software sprite image
_DEST HWSprite '                                                   draw on temp hardware sprite image
LOCATE 2, 2: PRINT "HARD"; '                                       print inside circle
CIRCLE (24, 24), 24 '                                              draw circle
_DEST SWSprite '                                                   draw on temp software sprite image
LOCATE 2, 2: PRINT "SOFT"; '                                       print inside circle
CIRCLE (24, 24), 24 '                                              draw circle
_DEST 0 '                                                          draw on main screen canvas
FOR c = 1 TO TOTAL '                                               cycle through sprites
    SpriteSW(c) = _COPYIMAGE(SWSprite, 32) '                       copy the software sprite
    SpriteHW(c) = _COPYIMAGE(HWSprite, 33) '                       copy the hardware sprite (notice 33)
    SpriteXY(c).x = SWIDTH / 2 - 24 '                              x coordinate start (centered)
    SpriteXY(c).y = SHEIGHT / 2 - 24 '                             y coordinate start (centered)
    SpriteXY(c).xdir = RND - RND '                                 random x vector from -1 to 1
    SpriteXY(c).ydir = RND - RND '                                 random y vector from -1 to 1
NEXT c
_FREEIMAGE SWSprite '                                              temp sprites no longer need
_FREEIMAGE HWSprite
f = 0 '                                                            reset frame counter
t = TIMER(.001) '                                                  get frame start time
DO '                                                               begin frame loop
    c = 0 '                                                        reset sprite counter
   IF Software THEN CLS '                                          software surface need clearing
   DO '                                                            begin sprite draw loop
        c = c + 1 '                                                increment sprite counter
       IF Software THEN '                                          software mode?
           _PUTIMAGE (SpriteXY(c).x, SpriteXY(c).y), SpriteSW(c) ' yes, draw software sprite
       ELSE '                                                      no
           _PUTIMAGE (SpriteXY(c).x, SpriteXY(c).y), SpriteHW(c) ' draw hardware sprite
       END IF
        SpriteXY(c).x = SpriteXY(c).x + SpriteXY(c).xdir '         move sprite by set vectors
        SpriteXY(c).y = SpriteXY(c).y + SpriteXY(c).ydir
       IF SpriteXY(c).x > SWIDTH - 50 OR SpriteXY(c).x < 1 THEN '  sprite going off screen?
            SpriteXY(c).xdir = -SpriteXY(c).xdir '                 yes, keep sprite on screen
       END IF
       IF SpriteXY(c).y > SHEIGHT - 50 OR SpriteXY(c).y < 32 THEN
            SpriteXY(c).ydir = -SpriteXY(c).ydir
       END IF
   LOOP UNTIL c = TOTAL '                                          leave when all sprites drawn
    f = f + 1 '                                                    increment frame counter
   IF TIMER(.001) >= t + 1 THEN '                                  has one second passed?
        tf = f '                                                   yes, record total frames
        f = 0 '                                                    reset frame counter
        t = TIMER(.001) '                                          get frame start time
   END IF
   LOCATE 2, 28: PRINT tf; "FPS" '                                 print FPS counter
   LOCATE 1, 2 '                                                   print instructions
   PRINT "Controlling"; TOTAL; "sprites. Press 'H' for hardware or 'S' for software - ESC to quit"
   _DISPLAY '                                                      update screen with changes
    a = UCASE$(INKEY$) '                                           get user key press (if any)
   IF a = "S" THEN Software = -1 '                                 if S pressed set software mode
   IF a = "H" THEN Software = 0: CLS '                             if H pressed set hardware mode
LOOP UNTIL a = CHR$(27) '                                          leave when user presses ESC key
FOR c = 1 TO TOTAL '                                               cycle through sprites
   _FREEIMAGE SpriteSW(c) '                                        remove sprites from RAM
   _FREEIMAGE SpriteHW(c)
NEXT c
SYSTEM '                                                            return to operating system

Figure 1: Controlling 8000 Sprites

Now that I have your attention let's learn how to use these powerful hardware rendering routines offered by QB64.

Surfaces

QB64 offers three rendering surfaces to display graphics on; a software surface, a hardware surface, and an OpenGL surface. The software surface you are already familiar with, it's the SCREEN statement you've been using. All graphics you've created up to this point using a statement such as _NEWIMAGE() have been created in software mode. A second surface, called the hardware surface, by default sits just above the software, or SCREEN, surface. Finally, a third surface for OpenGL rendering by default sits just above the hardware surface. QB64's OpenGL use will be discussed in a later lesson, for now we are only interested in the software and hardware surfaces. As you can see in Figure 2 below, these surfaces are presented as layers to the programmer.

Figure 2: QB64 Surfaces

The _DISPLAYORDER Statement

Again, by default, the software surface is the first surface drawn, followed by graphics from the hardware surface being drawn on top of the software surface. The _DISPLAYORDER statement is used to rearrange the surface layering order and/or include or exclude surfaces from being rendered at all. The surfaces themselves are referenced through the parameter names _SOFTWARE, for the software surface, and _HARDWARE, for the hardware surface.

Note: Once again we'll be dealing with the _GLRENDER surface in a later lesson. Also, if you visit _DISPLAYORDER in the QB64 Wiki you'll notice there is a fourth surface named _HARDWARE1. While the _DISPLAYORDER statement recognizes this surface as a valid parameter it's not yet implemented and is reserved for future use.

_DISPLAYORDER's use is very straightforward. The default statement is configured as:

_DISPLAYORDER _SOFTWARE , _HARDWARE ' Display software images first, hardware images second

To change the order simply issue the statement in reverse:

_DISPLAYORDER _HARDWARE , _SOFTWARE ' Display hardware images first, software images second

If you omit a surface parameter then only the surface parameter(s) included will be drawn:

_DISPLAYORDER _HARDWARE '             Display only hardware images
_DISPLAYORDER _SOFTWARE '             Display only software images

Note: QB64 defaults to _DISPLAYORDER _SOFTWARE, _HARDWARE so there is no need to issue this command if that is the surface order you wish to use.

The following example program allows you to change the display order and view the results on screen.

( This code can be found at .\tutorial\Lesson22\HWExample1.bas )

OPTION _EXPLICIT

' Example 1
' Hardware image persistence and display order

DIM SoftwareBox AS LONG ' software image
DIM HardwareBox AS LONG ' hardware image
DIM TempBox AS LONG '     temporary image to draw other images
DIM Count AS INTEGER '    generic counter
DIM x AS INTEGER '        location of images on screen
DIM dir AS INTEGER '      direction of images on screen

SCREEN _NEWIMAGE(640, 480, 32) '                 create the main screen (software surface)

'+------------------------------------------------------------------------------------------------------------+
'| Create two 320x200 images, one a software image, the other a hardware image                                |
'+------------------------------------------------------------------------------------------------------------+

TempBox = _NEWIMAGE(320, 200, 32) '              create a temporary software image
_DEST TempBox '                                  draw on the temporary image
CLS , _RGB32(0, 0, 255) '                        clear it with a blue background
COLOR _RGB32(255, 255, 0), _RGB32(0, 0, 255) '   set text color to yellow on blue
LOCATE 2, 1 '                                    position cursor
FOR Count = 1 TO 40 '                            print 40 times on temporary image
   PRINT " Software "; '                         print the word
NEXT Count
LINE (0, 0)-(319, 199), _RGB32(255, 255, 0), B ' put a yellow border around the image
SoftwareBox = _COPYIMAGE(TempBox, 32) '           copy temporary software image to a software image (notice 32)
LOCATE 2, 1 '                                    eposition cursor
FOR Count = 1 TO 40 '                            print 40 times on temporary image
   PRINT " Hardware "; '                         print the word
NEXT Count
LINE (0, 0)-(319, 199), _RGB32(255, 255, 0), B ' redraw the yellow border
HardwareBox = _COPYIMAGE(TempBox, 33) '          copy temporary software image to a hardware image (notice 33)
_DEST 0 '                                        go back to drawing on the main screen
_FREEIMAGE TempBox '                             temporary image no longer needed

'+------------------------------------------------------------------------------------------------------------+
'| The display order of software and hardware images can be set using the _DISPLAYORDER statement. The        |
'| default display order is to draw software images first and then hardware images second. This has the       |
'| effect of drawing software images in the background (UNDER) and hardware images in the foreground (OVER).  |
'| Basically, the last surface identified using _DISPLAYORDER will have its images on top of all surfaces.    |
'+------------------------------------------------------------------------------------------------------------+

'+------------------------------------------------------------------------------------------------------------+
'| Enable the following line for the default display order                                                    |
'+------------------------------------------------------------------------------------------------------------+

_DISPLAYORDER _SOFTWARE , _HARDWARE '             HARDWARE images appear ON TOP of SOFTWARE images (default)

'+------------------------------------------------------------------------------------------------------------+
'| Enable the following line to reverse the default display order (disable the line above)                    |
'+------------------------------------------------------------------------------------------------------------+

'_DISPLAYORDER _HARDWARE , _SOFTWARE '            SOFTWARE images will appear ON TOP of HARDWARE images

x = 0 '                                           set x location of software image
dir = 1 '                                         set movement direction of software image
DO
   _LIMIT 30
    '+--------------------------------------------------------------------------------------------------------+
    '| You'll notice that the software image is leaving a trail of yellow behind it (artifacts) while the     |
    '| hardware is not. The hardware surface will automatically move a hardware image from one location to    |
    '| another without leaving any sign where the image previously was. A "self-cleaning" method so to speak  |
    '| because the GPU discards the image immediately. The software surface does not have this "self-cleaning"|
    '| ability and therefore must be maintained by the programmer to keep artifacting from happening. A       |
    '| simple CLS statement will accomplish this.                                                             |
    '+--------------------------------------------------------------------------------------------------------+

    '    +----------------------------------------------------------------------------------------------------+
    'CLS '| Enable this line of code to keep the software image from artifacting                               |
    '    +----------------------------------------------------------------------------------------------------+

    '+--------------------------------------------------------------------------------------------------------+
    '| Notice that when you activated the CLS statement above the software image now begins to flicker too.   |
    '| The _DISPLAY statement explained below will clear this up as well.                                     |
    '+--------------------------------------------------------------------------------------------------------+

    x = x + dir '                                 a few lines of code to keep the images moving back and forth
   IF x = 320 OR x = 0 THEN dir = -dir

   _PUTIMAGE (x, 100), SoftwareBox '             the software surface is persistent
   _PUTIMAGE (320 - x, 179), HardwareBox '       the hardware surface is NOT persistent

    '+--------------------------------------------------------------------------------------------------------+
    '| You'll notice the hardware image is flickering. This is because the hardware surface will              |
    '| automatically clear itself. _DISPLAY must be used in order to retain hardware images until the next    |
    '| screen update. Remove the remark from the line below to see that the flickering has disappeared.       |
    '+--------------------------------------------------------------------------------------------------------+

    '          +----------------------------------------------------------------------------------------------+
    '_DISPLAY ' | Enable this line to continuing showing hardware images between screen updates                |
    '          +----------------------------------------------------------------------------------------------+

    '+--------------------------------------------------------------------------------------------------------+
    '| When the _DISPLAY statement above is active all drawing events to the screen are held in a queue. When |
    '| the code reaches the _DISPLAY statement all drawing events are performed at once. This keeps multiple  |
    '| hardware images from disappearing on the hardware surface during drawing (see HWExample2.BAS).         |
    '+--------------------------------------------------------------------------------------------------------+

LOOP UNTIL _KEYDOWN(27) '                         exit when the ESC key is pressed

Figure 3: Software Images Under Hardware Images

By enabling and disabling the _DISPLAYORDER statements on lines 49 and 55 you can see how the rendering order of the images change based on the surface order provided to _DISPLAYORDER. If you're wondering why it would be beneficial to change the surface display order it's because hardware and software images both have their own unique advantages and disadvantages that we'll be discussing soon.

Keep this program loaded as we'll be using it again shortly below.

Creating Hardware Images

The first thing to understand about hardware images is their limitation. Once a hardware image has been created it can't be changed. You can't PAINT, draw LINEs, CIRCLEs, PSET pixels, nothing. They are set in stone so to speak once created. Think of a hardware image as a fixed sprite that can be displayed, moved around, and deleted when not needed, that's it. It's this limitation that makes them so darn fast however. QB64 tells the video card to create the image in video RAM. When that image is needed the video card knows exactly where it is and displays a copy of the image directly to the video screen. QB64 doesn't have to do anything beyond telling the video card to display the image, the heavy lifting is done by the GPU. However, because the image now sits in the video card's RAM it's not accessible any longer for modifications, hence being set in stone.

Hardware images are created using the exact same methods of creating software images you are already familiar with. Only a slight change is required to tell QB64 that the image should be hardware based instead of software based. The _LOADIMAGE and _COPYIMAGE statements from Lesson 13 allow the creation of hardware images.

_LOADIMAGE Revisited

You've already learned how to use the _LOADIMAGE statement but here is the syntax again as a refresher:

Handle& = _LOADIMAGE(Filename$, Mode%)

To load a 32 bit color software image using _LOADIMAGE the following is issued:

MySWImage& = _LOADIMAGE(".\tutorial\Lesson13\sky.png", 32) ' 32 bit color SOFTWARE image

By setting the Mode% to 32 (or less) _LOADIMAGE was instructed to load a software image. To load a hardware image you simply change the Mode% value to 33:

MyHWImage& = _LOADIMAGE(".\tutorial\Lesson13\sky.png", 33) ' 32 bit color HARDWARE image

QB64 will now remember that this image is hardware based and needs to be displayed on the hardware surface when instructed.

_COPYIMAGE Revisited

The second method to create a hardware image is to use the _COPYIMAGE statement with a Mode% value of 33:

SoftwareImage& = _NEWIMAGE(64, 64, 32) '          create a software image
'                                                 your code here to draw graphics onto the image
HardwareImage& = _COPYIMAGE(SoftwareImage&, 33) ' copy the software image to a hardware image

This method comes in handy for tasks such as extracting sprites from a sprite sheet. Extract the individual sprites from the sheet as software images and then convert them to hardware using _COPYIMAGE as needed for example.

Image Persistence

When images are placed onto the software surface, the SCREEN, they stay visible until acted upon by the program. Even when the program exits using the END statement, and "Press any key to continue..." is displayed at the bottom of the screen, the images are still there. This is one of the reasons software rendered images are much slower than hardware rendered images. The CPU and QB64 are constantly updating the software images on the screen for you in the background. It takes a lot of CPU time to perform these updates but makes working with software images easy. If you require moving software images it's up to you as the programmer to clear the screen at the beginning of each frame and then redraw the software image in its new location. Up to this point that's what this tutorial has taught you to do.

The hardware surface acts much differently however. When a hardware image is displayed on the hardware surface the image only appears for one video screen refresh period, a few milliseconds at the most. The hardware image will then disappear because the video card doesn't keep refreshing the hardware surface with hardware images like QB64 and the CPU do for software images. This eliminates the need to keep clearing the hardware surface but presents a new problem; how do you draw multiple images to the hardware surface without them disappearing on you?

_DISPLAY Revisited

The answer, the same way you have been all along. Just as Lesson 5 discussed how the _DISPLAY statement queues up graphics for the software surface it also does this for the hardware surface. The program you currently have in your IDE, HWExample1.BAS from above, will let you play around with these concepts as well.

The software image is leaving a yellow trail behind it, something known as a visual artifact. An easy fix for this is to clear the software surface at the beginning of each loop using a CLS statement. Enable the CLS statement on line 71 of the program and the visual artifacts will disappear. The hardware image does not suffer from visual artifacts because it is automatically cleared after every video screen refresh. If you were to write a game using nothing but hardware images imagine the speeds you could obtain by eliminating the need to clear the screen after each animation loop along with the blazing update speeds of hardware images.

Now, there is still the problem of flicker to contend with. Easy, just enable the _DISPLAY statement in line 92 of the program. Visual artifacts on the software surface are now solved along with flickering and image updating of both surfaces taken care of by the _DISPLAY statement.

Here is another example program that shows the use of hardware images, software images, and how image persistence comes into play.

( This code can be found at .\tutorial\Lesson22\HWExample2.bas )

OPTION _EXPLICIT

' Example 2
' Software surface vs hardware surface

DIM HardwareBox AS LONG ' hardware image
DIM SoftwareBox AS LONG ' software image
DIM TempBox AS LONG '     temporary image to draw other images
DIM Count AS INTEGER '    generic counter

SCREEN _NEWIMAGE(640, 480, 32) '                  create the main screen (software surface)

'+------------------------------------------------------------------------------------------------------------+
'| Create two 320x200 images, one a software image, the other a hardware image                                |
'+------------------------------------------------------------------------------------------------------------+

TempBox = _NEWIMAGE(320, 200, 32) '               create a temporary software image
_DEST TempBox '                                   draw on the temporary image
CLS , _RGB32(0, 0, 255) '                         clear it with a blue background
COLOR _RGB32(255, 255, 0), _RGB32(0, 0, 255) '    set text color to yellow on blue
LOCATE 2, 1 '                                     position cursor
FOR Count = 1 TO 40 '                             print 40 times on temporary image
   PRINT " Software "; '                          print the word
NEXT Count
LINE (0, 0)-(319, 199), _RGB32(255, 255, 0), B '  put a yellow border around the image
SoftwareBox = _COPYIMAGE(TempBox, 32) '           copy temporary software image to a software image (notice 32)
LOCATE 2, 1 '                                     reposition cursor
FOR Count = 1 TO 40 '                             print 40 times on temporary image
   PRINT " Hardware "; '                          print the word
NEXT Count
LINE (0, 0)-(319, 199), _RGB32(255, 255, 0), B '  redraw the yellow border
HardwareBox = _COPYIMAGE(TempBox, 33) '           copy temporary software image to a hardware image (notice 33)
_DEST 0 '                                         go back to drawing on the main screen
_FREEIMAGE TempBox '                              temporary image no longer needed

'+------------------------------------------------------------+
'| Draw three software images to the software surface outside |
'| of a loop. Remember that the SCREEN is the software        |
'| surface. The software surface is maintained by the CPU and |
'| QB64 itself through underlying code.                       |
'+------------------------------------------------------------+

PRINT "              3 Software images drawn 1/10th of a second apart"
_PUTIMAGE (0, 20), SoftwareBox '        draw software images to the software surface (the SCREEN)
_DELAY .1
_PUTIMAGE (159, 139), SoftwareBox
_DELAY .1
_PUTIMAGE (319, 259), SoftwareBox
_DELAY .1
LOCATE 24, 2: PRINT "Once a software image is drawn"
LOCATE 25, 2: PRINT "it persitently stays on the screen"
LOCATE 26, 2: PRINT "with no updating or redrawing needed."
LOCATE 28, 2: PRINT "Hardware images next, press a key..."
SLEEP
CLS

'+------------------------------------------------------------+
'| Draw three hardware images to the hardware surface outside |
'| of a loop. Remember that hardware images have their own    |
'| hardware surface completely independent from the software  |
'| surface. The hardware surface is maintained by the GPU.    |
'+------------------------------------------------------------+

PRINT "              3 Hardware images drawn 1/10th of a second apart"
_PUTIMAGE (0, 20), HardwareBox '        draw hardware images to the hardware surface in the GPU
_DELAY .1
_PUTIMAGE (159, 139), HardwareBox
_DELAY .1
_PUTIMAGE (319, 259), HardwareBox
_DELAY 1.1
LOCATE 24, 2: PRINT "Where are they?"
SLEEP 2
LOCATE 25, 2: PRINT "Hardware images are maintained by the"
LOCATE 26, 2: PRINT "GPU. They are displayed and then discarded."
LOCATE 28, 2: PRINT "Press a key...."
SLEEP

'+------------------------------------------------------------+
'| Draw three hardware images to the hardware surface inside  |
'| of a loop. The _DISPLAY statement needs to be used to      |
'| queue the images. Without the _DISPLAY statement in the    |
'| loop below the hardware images will flicker because the    |
'| GPU will remove them immediately after they are drawn.     |
'+------------------------------------------------------------+

CLS
PRINT "                   3 Hardware images drawn using a queue"
LOCATE 24, 2: PRINT "You need to queue them up using"
LOCATE 25, 2: PRINT "_DISPLAY inside of a loop after"
LOCATE 26, 2: PRINT "all the images have been drawn."
LOCATE 28, 2: PRINT "Press ESC to exit...."

DO
   _LIMIT 15 '                         limit CPU to keep from overheating
   _PUTIMAGE (0, 20), HardwareBox '    draw hardware images to the _DISPLAY queue
   _PUTIMAGE (159, 139), HardwareBox
   _PUTIMAGE (319, 259), HardwareBox

    '+--------------------------------------------------------+
    '| Disable the _DISPLAY statement below to see the        |
    '| flickering mentioned above.                            |
    '+--------------------------------------------------------+

   _DISPLAY '                          dump hardware images to the GPU, software images to the SCREEN
LOOP UNTIL _KEYDOWN(27)

'+------------------------------------------------------------+
'| When we leave the loop there is nothing refreshing the     |
'| hardware surface so the GPU instantly clears the images.   |
'+------------------------------------------------------------+

_AUTODISPLAY '                          give screen update control back to QB64
LOCATE 16, 8: PRINT "Notice how the hardware images disappeared when we left the loop."
LOCATE 18, 5: PRINT "Remember that hardware images are not persistent and will be discarded."
SLEEP 2
END

The code above highlights how software images will remain on the software surface indefinitely until actively changed by the program. Hardware images on the other hand will not remain on the hardware surface and need to be refreshed to keep them visible on the screen.

Hardware/Software Examples

Remember the Hocus Pocus example program from Lesson 14? The code has been modified to use hardware images and only the hardware surface. You won't notice a speed difference in the particle effects due to the _LIMIT 60 statement in the main program loop controlling the overall speed of the program. The main advantage to using hardware images and the hardware surface in this program is manually clearing ( CLS ) of the screen from one frame to the next is not needed. The CLS statement, for what little it seems to do, actually takes a good junk of CPU time to complete. The use of hardware images also drastically reduces the CPU usage (more detail on that in a little bit). The program HWHocusPocus.BAS can be found in your .\tutorial\Lesson22 subdirectory.

Note: You'll also notice other changes in the Hocus Pocus program below from the version in Lesson 14. I wrote the original code 10 years ago and have learned a few optimization tricks since then. You never stop learning and improving, no matter what your skill level is.

More Power!

Included in your .\tutorial\Lesson22 subdirectory are two programs, one called SWPicture.BAS and the other HWPicture.BAS, created to show the advantages of hardware images vs software images.

Besides being faster, the use of hardware images is also much less taxing on your CPU, leaving that extra CPU horsepower at your disposal for other intensive tasks such as 2D, 3D, and vector math calculations.

Both of these programs deconstruct an image into 20x20 individual images and rapidly move the individual images around at full speed (the deconstruction phase) using no FPS limiting. SWPicture.BAS is the software image and surface version of the program and HWPicture.BAS is the hardware image and surface version of the program.

Go ahead and load each program version and execute it. To use the the programs do the following:

While each program is running in the deconstruction phase view the CPU usage in your Task Manager in Windows or Table of Processes (TOP) in Linux. On my computer using Windows the software version uses 34% of the CPU while the hardware version uses 25% of the CPU, close to a 10% decrease in CPU usage simply by using hardware images. However, both of these programs have no FPS limits set on them and they are free to use as much CPU time as they like. In almost all cases, especially games, an FPS limit will be set using the _LIMIT statement to slow things down to a manageable speed so the player can make sense of the action going on.

On line 20 of each program change the constant LIMIT to equal the value of -1:

CONST LIMIT = -1 '                 set to -1 to impose a 250 FPS limit

After changing the constant run each program again and view the CPU usage in Task Manager or TOP during the deconstruction phase. On my computer the software version uses 30% of the CPU while the hardware version uses just 12% of the CPU! Nearly a 60% reduction in CPU usage! This alone is a huge reason to use hardware images as much as possible when developing games. All of that extra CPU horsepower is now at your disposal.

Figure 4: The Deconstruction Phase

Commands and Concepts Learned

New commands introduced in this lesson:

_DISPLAYORDER
_SOFTWARE
_HARDWARE
_GLRENDER
_LOADIMAGE (with mode of 33)
_COPYIMAGE (with mode of 33)

New concepts introduced in this lesson:

Hardware Images
Visual Artifact