Posts: 1,277
Threads: 120
Joined: Apr 2022
Reputation:
100
I'm working on the hardware acceleration tutorial lesson.
According to the Wiki _DISPLAYORDER has the following default surface order:
_DISPLAYORDER _SOFTWARE, _HARDWARE, _GLRENDER, _HARDWARE1
_SOFTWARE - I understand
_HARDWARE - I understand
_GLRENDER - I sort of understand
_HARDWARE1 - What is this?
Where does _HARDWARE1 come into play and how would I utilize it?
Also, the Wiki points out that _DISPLAYORDER can be used as:
_DISPLAYORDER [{_SOFTWARE|_HARDWARE|_HARDWARE1|_GLRENDER}][, ...][, ...][, ...][, ...]
Does this somehow mean that the four surfaces above can be listed and used more than once? If so, how the heck does that work?
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 1,277
Threads: 120
Joined: Apr 2022
Reputation:
100
Here are a couple of tutorial programs I have created so far. Please let me know if you notice something wrong in either of them.
Code: (Select All) OPTION _EXPLICIT
' Example 1
' Hardware image persistance 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 the 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 the 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 other surfaces. |
'+-------------------------------------------------------------------------------------------------------------------------+
'+-------------------------------------------------------------------------------------------------------------------------+
'| Enable the following line for the default display order |
'+-------------------------------------------------------------------------------------------------------------------------+
_DISPLAYORDER _SOFTWARE , _HARDWARE ' HARDWARE images will appear ON TOP of SOFTWARE images (this is 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 immediatly. |
'| 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 persistant
_PUTIMAGE (320 - x, 179), HardwareBox ' the hardware surface is NOT persistant
'+---------------------------------------------------------------------------------------------------------------------+
'| 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 HWLesson2.BAS to see an example. |
'+---------------------------------------------------------------------------------------------------------------------+
LOOP UNTIL _KEYDOWN(27) ' exit when the ESC key is pressed
Code: (Select All) 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 the 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 the 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 immediatly 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
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
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 2,686
Threads: 326
Joined: Apr 2022
Reputation:
215
Ah, the good old memories of a man who feels like he's got dementia! Youngster, let me tell you a story!
Back in the early days of the world; back when I was just a little child roaming the foggy hills of creation, there was a God which walked amongst us. This God was named Galleon and all his creations were good. It's only thanks to the grace that Galleon bestowed upon us that mankind, the pitiful programmers that we were, managed to learn the power and control PRINT "Hello World" could bring to our pitiful BASless existence!
In those early days, Galleon began working within what he called the "SDL Framework", and all was good -- at first! Over time, the very programmers that had been drawn to the tools which Galleon had created with his own hard blood, sweat, and tears, turned against his works! "Lord Galleon," they protested, "we can not stand to have to package library files with our executables! You must do something to allow us to create stand-alone EXEs! Nobody wants to have to archive all their work up into packages to share it, and even as programmers, we're not able to figure out how to place those required files into the PATH on our OS!"
And Lo! Galleon heard the cries of the masses and swapped out the SDL Framework for a newer GL Framework. And the people rejoiced!
Or not... People are peoples, first and foremost. They cry out in dissatisfaction; nor in contentment. A great mass of voices rose to the heavens again! "Lord Galleon, this routine isn't working as it used to. I don't think this has been implemented in the swap-over! GL SUCKS -- MY STAND ALONE EXE IS TOO LARGE NOW!!"
And Lord Galleon was bewildered by the people's many voices. It had taken years to create the SDL Framework, and yet the peoples weren't willing to give even a few paltry months to give time to fully convert over to the new GL Framework? Feeling as if he was rushing to put out flames of discontent, Lord Galleon dropped things that he was attempting to work upon, to answer the relentless calls to "fix" that which others felt was broken. Many ambitious new commands which were destined to be great additions to the tools which Galleon had created, were put on hold and only partially implemented.
The single unbroken vision which was "QB64" was shattered, and became "Dirty". There was creation of what was known as "Stable Builds", and then there was the shadow of darkness which was the "Dirty Builds", which contained ideas in embryo! Concepts which were all part of the great plan that was Galleon's, but which hadn't fully became part of existence.... yet!
And yet, the masses were not satisfied. No matter how hard Galleon ran around in circles attempting to fix things, so he could move on in the forward direction that he envisioned (such as porting programs to Android devices), the peoples kept relentlessly crying out in protest over one minute issue after another!!
Finally, as Galleon received a job offer upon the other end of the continent where he existed, He decided, "Enough is enough. The greatness that is *I*, is done! Do with my works what you will!" And thus, he walked out into the sunset, seldom if ever heard from again.
And for those who can't piece together what happened via "Steve Story Time", let me break it down simply.
_DisplayOrder, _GL, _Hardware, and _Hardware1 were all added into the language back when we transitioned over from SDL to GL. For those folks who remember the "Dirty Builds" back in those days, those were the versions which Galleon used to push development updates and changes into the language, until they reached a point that he felt was stable enough to become part of the main language.
In some of those Dirty Builds, there were options which I remember for _COPYIMAGE(handle, 34) and _LOADIMAGE(image$, 34). This old timer remembers Galleon even provided a demo of a zebra and a spaceship (I think it was a spaceship. I swear, I don't remember fully now, but I absolutely remember that zebra model!), and how you could rotate the images and display them with various Z-order using the _DISPLAYORDER command.
_Hardware was created with _COPYIMAGE(handle, 33)
_Hardware1 worked exactly the same, but it was placed upon a separate page via _COPYIMAGE(handle, 34)
It was that toggle between 33 and 34 which specified which of the hardware layers our resources rendered to, and then we could set the Z-order with _DISPLAYORDER.
**I** swear, I remember seeing those commands with that syntax. I even remember writing up a demo and sharing it on the old .net forums which Galleon maintained, which did the same thing as his zebra demo, but with various colored boxes instead. There was a red box, blue box, white box, and you could toggle their Z-order with just a few keystrokes and place whichever one you wanted on top of another...
But, back in those final days of the language, just as things were getting swapped over from SDL to GL, there also existed massived server issues. If you guys remember, our forums would crash every so often and disappear. The codebase wasn't on github back then, but on Google Code instead -- and Google Code was shutting down and forcing migrations. You could post work on the forums on Monday, view it until Thursday, then have the forums go down and when they went back up two weeks later, notice that what you'd shared just evaporated...
Somewhere in that time, _HARDWARE1 just.... evaporated. It *was* a part of the language. It was accessed via _COPYIMAGE(handle, 34), as far as my poor old memories assure me. It's just that sometime between when it was first added, and *NOW*, it... poofed! I've asked about it several times, and me and the other devs have looked into it a couple of times, and it's just... missing, as far as I can tell you!
(Think that's odd? WE have whole commands that were under development which went missing such as the _MOUSEPIPEINPUT, and other commands that are only partially implemented behind the scenes such as _FPS.) As far as I can piece together, what happened was: Galleon was working on adding these new additions into the language, but they were part of the "Dirty builds" and not considered "Stable" yet. When Google Code transferred the codebase over to Github, we only got the "Stable" version of stuff. Things in development such as _HARDWARE1 never got pushed over and didn't make the transition, and that -- along with everyone's whining and complaining -- was enough for Galleon to just decide "I'm done. /Blah!"
With Galleon leaving, the rest of us tried to pick up the pieces and learn the language and continue one as much as possible like before. Things such as _HARDWARE1 hadn't never actually became part of the "Stable" language (though it'd already been documented and was part of the "Dirty Builds", and as such they just kind of got lost in the shuffle of learning the codebase and rebuilding and expanding the language as we could. Honestly, I think it was probably several years before anyone even asked about, "What the heck happened to _HARDWARE1?", and at that point 99.9% of the user base had completely forgotten it existed.
The plan was always to reimplement that extra Z-layer so folks could have more flexibility in writing their programs, but life happens. Fellippe walked away. RC burned down our home (again). Developers only have so much time to devote to working on the language, which is a hobby for them, and as of yet, _HARDWARE1 is still a missing command option. It's never been removed from the wiki, as the plan is to put it back into the language, but at the moment, it's just... lost. I don't recall now if there's stubs for it in the codebase, or half-finished implementations, or if it's just all been reverted out of the language, but at one point, *IT DID EXIST AS PART OF OUR LANGUAGE*.
It just doesn't exist right now, anymore.
Unless, of course, some other dev knows where the heck it's been hiding at and how to interact with it. *MY* old memories assure me of _COPYIMAGE(handle, 34), but it may have been worked on sometime in the past X years of missing development notes and now have plans for a completely different implementation. I honestly don't know what the BLEEP its status is anymore. It used to exist. Our wiki goes back far enough to document its existence. It just doesn't exist currently.
I blame Mars. Those dang aliens are sabotaging us, just to keep us from building spaceships to go conquer their world with QB64PE! They evaporated it from the current codebase!
Posts: 98
Threads: 1
Joined: Jun 2023
Reputation:
3
Terry Ritchie, Examples 1 and 2 works well. None of SMcNeil's Marvin Martian in them.
Posts: 1,587
Threads: 59
Joined: Jul 2022
Reputation:
52
Great story, Steve.
I had thought Galleon switched out of SDL into OpenGL because SDL v1 was becoming obsoleted and he didn't want to invest in it. Also that he had some problems with rendering the QB64 IDE. The SDL v2 (and probably less important, going from 32-bit to 64-bit) caused some problems of adjustment to at least one other developer... the Italian guy in charge of SDLBASIC.
It wouldn't have surprised me there were spoiled brats saying, "Why does QB64 have to play ancient tracker modules, huh? What does it owe to Amiga or Soundblaster? Bring up that darned quality of them MP3 and OGG files I purposely recorded at 64 kilobits per second!" I admit, the SDL support for the ancient tracker modules was a good bonus, but I struggled to find an use for it away from a simple media player that I built.
I would have liked to see the hardware layer implemented strictly from SDL. But the moving pictures out of Python programs using that graphics library would have to do more with its being an interpreter. Too bad Snakeware didn't boot for me...
Posts: 1,277
Threads: 120
Joined: Apr 2022
Reputation:
100
09-15-2023, 03:53 AM
(This post was last modified: 09-15-2023, 03:54 AM by TerryRitchie.)
(09-15-2023, 12:43 AM)GareBear Wrote: Terry Ritchie, Examples 1 and 2 works well. None of SMcNeil's Marvin Martian in them. Thank you for checking the programs out.
@SMcNeill Yeah I remember those days too. I never did understand the hate for having to include a few .DLL files along with the .EXE. I simply used Innosetup to compile a nice clean installer for the software I distributed. Hell, Innosetup even set up an uninstaller in the start menu for you as well. And best of all it was free.
I wish Galleon would have just continued to update on his own timeline and ignored all the requests/negativity/etc.. I often wonder if he has been working on his vision of what QB64 should be and will release it to the world some day.
Ok, so _HARDWARE1 is not implemented then. I'll be sure to include in the tutorial that even though the keyword is accepted it's a feature that's planned for the future. Having 2 (or more) hardware surfaces to work with would really be handy.
One other thing I noticed by accident. I was under the assumption that hardware images would not even display if the _DISPLAY statement was not used. Turns out they will but for a very, very brief time. You need to keep the image drawing in a very tight fast loop for it to do any good though. I'm going to instruct tutorial users that best practice is to use _DISPLAY with hardware images.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Posts: 2,686
Threads: 326
Joined: Apr 2022
Reputation:
215
09-15-2023, 04:11 AM
(This post was last modified: 09-15-2023, 04:11 AM by SMcNeill.)
@TerryRitchie Remember, when _DISPLAY isn't used, _AUTODISPLAY is the default.
What you're seeing is AutoDisplay triggering _Display, pushing the hardware image onto the screen, and then flushing it from memory. The next loop around, AutoDisplay triggers _Display, but there's no hardware image to sync and push with now. That's where the very, very brief display you're seeing is coming from.
Hardware images won't render without a call to _DISPLAY, but it doesn't matter if you do that call or if AutoDisplay does for you.
Posts: 1,277
Threads: 120
Joined: Apr 2022
Reputation:
100
(09-15-2023, 04:11 AM)SMcNeill Wrote: @TerryRitchie Remember, when _DISPLAY isn't used, _AUTODISPLAY is the default.
What you're seeing is AutoDisplay triggering _Display, pushing the hardware image onto the screen, and then flushing it from memory. The next loop around, AutoDisplay triggers _Display, but there's no hardware image to sync and push with now. That's where the very, very brief display you're seeing is coming from.
Hardware images won't render without a call to _DISPLAY, but it doesn't matter if you do that call or if AutoDisplay does for you. Ahhh, gotcha, that makes complete sense. I'll make sure to explain this in the tutorial as another emphasis for using _DISPLAY as a best practice.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
|