Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Hardware Images
#1
Someone on Discord sent me a couple of messages asking what the big deal was with hardware images, and why anyone would ever bother with them.   I hope the little demo below here will be sufficient enough to showcase why folks might want to make use of hardware images in their programs.

Code: (Select All)
DIM count AS _INTEGER64
displayScreen = _NEWIMAGE(1024, 720, 32)
workScreen = _NEWIMAGE(512, 360, 32)

SCREEN displayScreen
_DEST workScreen
FOR i = 1 TO 100 'draws something on the drawscreen
    LINE (RND * _WIDTH, RND * _HEIGHT)-(RND * _WIDTH, RND * _HEIGHT), _RGB32(RND * 256, RND * 256, RND * 256), BF
NEXT
hardwareScreen = _COPYIMAGE(workScreen, 33)

_DEST displayScreen

PRINT "For this demo, we're going to be scaling and placing a premade image onto the screen."
PRINT "For ease of output, our FPS count is going to be placed up in the TITLE area."
PRINT
PRINT "First, we'll do a FPS cound of simple software images."
PRINT "Let it run a few seconds, and then press <ANY KEY> when you'd like to move on."
PRINT
PRINT "After that, we'll use hardware images AND software images, and see how things compare."
PRINT "As before, watch the TITLE area for updates, and press <ANY KEY> when ready to move on."
PRINT
PRINT "And finally, we'll JUST use hardware images for our display."
PRINT "Once again, our FPS second count will be in the TITLE area, and you can press <ANY KEY> to"
PRINT "move to our final resulsts screen for ease of comparison."
PRINT
PRINT
PRINT "Press <ANY KEY> to begin."
SLEEP

_DELAY .5
_KEYCLEAR 'time to release any key


time# = TIMER + 1
DO
    CLS , 0
    scount = scount + 1
    IF TIMER > time# THEN
        _TITLE "Software FPS:" + STR$(scount)
        IF scount > smax THEN smax = scount
        scount = 0
        time# = TIMER + 1
    END IF
    _PUTIMAGE , workScreen
    _DISPLAY
LOOP UNTIL _KEYHIT

_DELAY .5
_KEYCLEAR 'time to release any key

time# = TIMER + 1
DO
    CLS , 0
    mcount = mcount + 1
    IF TIMER > time# THEN
        _TITLE "Mixed FPS:" + STR$(mcount)
        IF mcount > mmax THEN mmax = mcount
        mcount = 0

        time# = TIMER + 1
    END IF
    _PUTIMAGE , hardwareScreen
    _DISPLAY
LOOP UNTIL _KEYHIT

_DELAY .5
_KEYCLEAR 'time to release any key

time# = TIMER + 1
_DISPLAYORDER _HARDWARE
CLS , 0
DO
    hcount = hcount + 1
    IF TIMER > time# THEN
        _TITLE "Hardware FPS:" + STR$(hcount)
        IF hcount > hmax THEN hmax = hcount
        hcount = 0
        time# = TIMER + 1
    END IF
    _PUTIMAGE , hardwareScreen
    _DISPLAY
LOOP UNTIL _KEYHIT

_DISPLAYORDER _SOFTWARE , _HARDWARE
CLS , 0
_AUTODISPLAY

PRINT USING "###,###,### FPS with Software Images"; smax
PRINT USING "###,###,### FPS with Software and Hardware Images"; mmax
PRINT USING "###,###,### FPS with Hardware Images only"; hmax
PRINT
PRINT
PRINT "I would think the figures here alone, would showcase why one might want to use hardware images over other types, when possible."






[Image: image.png]
Reply
#2
Shocked 
No I'm not going to believe it's 2.5 million FPS on the last test! On a humble 10-year-old budget HP laptop. With desktop PC with GPU I would expect at least that much.
Reply
#3
(01-14-2023, 04:32 PM)mnrvovrfc Wrote: No I'm not going to believe it's 2.5 million FPS on the last test! On a humble 10-year-old budget HP laptop. With desktop PC with GPU I would expect at least that much.

Can't believe the numbers?  How about if I use some easy animation to showcase the difference for you?  Surely you'd be able to tell if a box was bouncing around the screen faster than it did previously.  Right?

Code: (Select All)
DIM count AS _INTEGER64
displayScreen = _NEWIMAGE(1024, 720, 32)
workScreen = _NEWIMAGE(100, 100, 32)

SCREEN displayScreen
_DEST workScreen
CLS , &HFFFFFF00
hardwareScreen = _COPYIMAGE(workScreen, 33)
_DEST displayScreen

PRINT "For this demo, we're going to be scaling and placing a premade image onto the screen."
PRINT "For ease of output, our FPS count is going to be placed up in the TITLE area."
PRINT
PRINT "First, we'll do a FPS cound of simple software images."
PRINT "Let it run a few seconds, and then press <ANY KEY> when you'd like to move on."
PRINT
PRINT "After that, we'll use hardware images AND software images, and see how things compare."
PRINT "As before, watch the TITLE area for updates, and press <ANY KEY> when ready to move on."
PRINT
PRINT "And finally, we'll JUST use hardware images for our display."
PRINT "Once again, our FPS second count will be in the TITLE area, and you can press <ANY KEY> to"
PRINT "move to our final resulsts screen for ease of comparison."
PRINT
PRINT
PRINT "Press <ANY KEY> to begin."
SLEEP

_DELAY .5
_KEYCLEAR 'time to release any key


time# = TIMER + 1
xdirection = 1
ydirection = 1
DO
    CLS , 0
    scount = scount + 1
    IF TIMER > time# THEN
        _TITLE "Software FPS:" + STR$(scount)
        IF scount > smax THEN smax = scount
        scount = 0
        time# = TIMER + 1
    END IF
    x = x + xdirection
    y = y + ydirection
    IF x >= _WIDTH THEN xdirection = -xdirection
    IF x <= 0 THEN xdirection = -xdirection
    IF y >= _HEIGHT THEN ydirection = -ydirection
    IF y <= 0 THEN ydirection = -ydirection
    _PUTIMAGE (x, y)-STEP(100, 100), workScreen
    _DISPLAY
LOOP UNTIL _KEYHIT

_DELAY .5
_KEYCLEAR 'time to release any key

time# = TIMER + 1
DO
    CLS , 0
    mcount = mcount + 1
    IF TIMER > time# THEN
        _TITLE "Mixed FPS:" + STR$(mcount)
        IF mcount > mmax THEN mmax = mcount
        mcount = 0

        time# = TIMER + 1
    END IF
    x = x + xdirection
    y = y + ydirection
    IF x >= _WIDTH THEN xdirection = -xdirection
    IF x <= 0 THEN xdirection = -xdirection
    IF y >= _HEIGHT THEN ydirection = -ydirection
    IF y <= 0 THEN ydirection = -ydirection
    _PUTIMAGE (x, y)-STEP(100, 100), hardwareScreen

    _DISPLAY
LOOP UNTIL _KEYHIT

_DELAY .5
_KEYCLEAR 'time to release any key

time# = TIMER + 1
_DISPLAYORDER _HARDWARE
CLS , 0
DO
    hcount = hcount + 1
    IF TIMER > time# THEN
        _TITLE "Hardware FPS:" + STR$(hcount)
        IF hcount > hmax THEN hmax = hcount
        hcount = 0
        time# = TIMER + 1
    END IF
    x = x + xdirection
    y = y + ydirection
    IF x >= _WIDTH THEN xdirection = -xdirection
    IF x <= 0 THEN xdirection = -xdirection
    IF y >= _HEIGHT THEN ydirection = -ydirection
    IF y <= 0 THEN ydirection = -ydirection
    _PUTIMAGE (x, y)-STEP(100, 100), hardwareScreen

    _DISPLAY
LOOP UNTIL _KEYHIT

_DISPLAYORDER _SOFTWARE , _HARDWARE
CLS , 0
_AUTODISPLAY

PRINT USING "###,###,### FPS with Software Images"; smax
PRINT USING "###,###,### FPS with Software and Hardware Images"; mmax
PRINT USING "###,###,### FPS with Hardware Images only"; hmax
PRINT
PRINT
PRINT "I would think the figures here alone, would showcase why one might want to use hardware images over other types, when possible."


See the difference in performance?
Reply
#4
And, if you think the last demo is "cheating" somehow by not drawing each box pixel by pixel, then simply go in and add a _LIMIT to that last loop.  Give it a _LIMIT 1000 or so, and it should be slow and smooth enough to watch as it makes the passes across the screen, without leaving afterimages in your eyes.  Wink
Reply
#5
Wowser, my budget HP laptop that is only about a year old is coming in over 5,000,000 fps!  I really have to take  more serious look at hardware images.
Reply
#6
In my investigations of hardware images, they have a somewhat higher learning curve to use, but are generally worth the investment. I doubt my billiards program would have flown so well without them.
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#7
OH MY GOD !!!!!

I have to try this in my starships game
10 PRINT "Hola! Smile"
20 GOTO 10
Reply
#8
Just remember guys -- the reason why the 3rd mode is running so fast, is because we're **ONLY** using hardware images with our rendering.

_DISPLAYORDER _HARDWARE   <-- see that there's no software screen at all in my display order here.

That means no printing to the screen.  No drawing boxes, or circles, or PSETing points.  Hardware images are preset images that don't change on us, so they're not the answer to every problem with speed out there.

For @Ikerkaz, it'd probably be a perfect solution for his needs and give him a nice speed boost -- displaying sprites of spaceships zooming back and forth across the screen.  For someone who was doing something like a database (like the teacher's gradebook in the other forum's that's been discussed a lot), that's going to require a lot of PRINT statements and user input, and really won't work very well without using a software screen.

For hardware only, you're basically going to be limited to using preset images only -- but if you can write and structure your code in such a manner as to make it work for you, you'll see the performance and speed increases to be a *very* noticeable improvement for your programs.  Hardware images aren't the solution for every program out there, but for the ones where they do make sense, *they make a whole lot of sense*!   Wink
Reply
#9
Folks are, once again, struggling to understand and work properly with hardware images.  Let's see if I can come up with a nice breakdown of the whole process from top to bottom, to help sort out whatever their problems might be.

1 -- First, Forget the FLUCK about _HARDWARE.  Forget about hardware images.  Forget even about QB64!!  We're going to take a large step back and start at the very beginning by going back to The School of Steve(tm).

Now, in the School of Steve (SOS for shorthand), teachers don't talk to students at all.  The only way they communicate is via writing stuff down and having the students read what they write.   And another oddball quirk about SOS is that they don't use erasable blackboards.  All the school board approves for them is unlimited paint (freely donated by the McNeill Paint Company), and a large sheet of glass and a few magic markers.

So how does the teachers communicate with these limitations, you ask?

Well, they can use paint and draw and print on the walls, or they can use the marker and scribble on the glass as needed.  Two completely separate mediums, with two completely different rulesets for working with them.  With the wall, if you want it to go back to being a blank canvas, you have to issue a command to one of the students -- "CLS"!  This will cause that student to get up and repaint that wall white -- or whatever color you specify for the background color.  With that glass sheet?  It cleans itself!  The marker is water based and evaporates quickly after use!

So obviously, it's plain to see that there's some major differences in the two mediums.  The wall is more permanent and persistent, but it requires more work to draw to and erase, while the glass sheet is very quick to scribble on, but has no lasting sustainability.

Congratulations!  You now understand one of the major differences in _HARDWARE and _SOFTWARE.

_SOFTWARE images are like that wall.  You paint on them.  Draw on them.  Do whatever you want on them.  And, when you're finished, the wall remains as you left it, until someone paints over it in the future.

_HARDWARE images are the glass sheet.  Much faster in their simplicity, but impermanent.  You make them.  _DISPLAY them.  They evaporate out of existence.

Two completely separate mediums, two completely separate rulesets for working with them.  Toss out everything you know about _SOFTWARE images, if you're going to be working with _HARDWARE images.  Once you've did that, then continue on below:




So, with your mind a blank slate, and with you now having no preconceptions of what a hardware image is, or what the ruleset is for working with one, let me give it to you:

1) A hardware image is an immutable image that can NOT change.  You finalize it and _LOADIMAGE (image, 33) or _COPYIMAGE(image, 33), to make it a hardware image.  You can't print to it.  Draw on it.  Or alter it in any way, shape, or form.  It's a finalized image.
2) A hardware image can only be rendered onto one place -- the _HARDWARE layer.  That's it.  No need to specify a handle for where you want to put it.  It either goes to the hardware layer for rendering, or else it explodes and melts your GPU.  It's *REAL* picky about where you can use it...
3) A hardware image is rendered ONLY when _DISPLAY is called, and then it's immediately purged from the GPU.

And...  honestly, that's it.

A lot simpler than software images, to be honest.  All you can do with them is load them and display them.  What's there to be confused about with that??



And with that said, folks *still* end up getting lost, as they're simply not used to working with such simple rulesets.  You often see people write code like:

Code: (Select All)
PRINT "X:"; X
PRINT "Y:"; Y
_DISPLAY 'print the software screen

_PUTIMAGE ,HardWare 'put the hardware screen in place
_DISPLAY 'show that hardware screen

And then they end up saying, "Why doesn't this work?  My hardware screen isn't drawing!!  Or why is it flickering like an old 1930s movie?!"

It is!  The thing is, it's drawing at the _DISPLAY after the call for the hardware screen, and then it's cleared out of the GPU.  (Rule Three above!)  When the print statements do their thing, they issue a separate _DISPLAY statement which has a blank hardware layer.  What you're doing is:

Update software screen with X and Y.
_DISPLAY software, hardware (hardware is blank)

Update hardware screen with the putimage.
_DISPLAY software(it hasn't changed), hardware

See the flicker in there?

Steve's Rule of Thumb here?  *Just use one _DISPLAY in your main loop.  Do all your drawing/printing and putimageing first, and then _DISPLAY everything with a single call.*




Second problem which folks seem to have -- learning to use layering properly.

Now, let's take a moment and step back to the School of Steve.  Did you know that we can do some very impressive layering with the newest paints that McNeill's Paint Company produces -- Invisible Transparency Z(tm)!

Now, we can paint our wall invisible, and then paint and draw on it where we want, so it looks like letters are just floating in midair!

And with the addition of our glass sheets, we can write on them with our markers and sit them in front of our walls!   

Or, we can have our students carry our glass sheets and sit them behind our invisible walls!  Either way, we can layer drawings now with our walls and our glass sheets!

Now, let's say I draw a big RED CIRCLE on my wall, and I draw a BLUE SQUARE on my glass sheet.  If my glass sheet is in front of the wall, what are my students going to see?

The BLUE SQUARE!  It's in front of the red circle and is going to block their view to it.

So what if I put my glass sheet on the other side and behind the wall?  What will the students see?

A RED CIRCLE inside a BLUE SQUARE!  The circle is in front of what portion of the square that it can cover, hiding that portion from view, with the rest of the edges of the square being visible to the class.

That's _DISPLAYORDER in a nutshell!

Hardware images and Software images are on independent layers.  You decide which one you want on top with the _DISPLAYORDER command.  Is the glass sheet on this side of that invisible wall, or is it on the other side and behind it?  



And here's the most common glitch we see with folks with _DISPLAYORDER:

Code: (Select All)
_DISPLAYORDER _HARDWARE
PRINT "X:"; X
PRINT "Y:"; Y

_PUTIMAGE ,HardWare
_DISPLAY

And the complaint here is, "Where's my debugging text?!!"

DUDE!!  You took a sledgehammer to the wall, tore it down, and hauled it out of the classroom!  You don't even HAVE a wall anymore!  With your _DISPLAYORDER statement, you decided you were only going to use hardware images because they're so much faster, and now you're wanting to make use of the software layer which you tossed out!

You can't draw on the wall you no longer have in your classroom.  I'm afraid that just doesn't work...
Reply
#10
Thumbs Up 
I'm going to do like vince:

SOS is now better than ...---...

It is the new "IN"!

So you all better learn. LOL.

(This last post is awesome, but a bit long, SMcNeill. I think it might have been better if you started a new topic with it, or you somehow indicated it as something important to read on the forum. Because somebody else would have posted after it like I just did and it has a better chance of being lost in the shuffle.)
Reply




Users browsing this thread: 3 Guest(s)