Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Cyborg)
  • No Skin
Collapse
Brand Logo

CIRCLE WITH A DOT

  1. Home
  2. Uncategorized
  3. I want to do some more stuff with Apricot graphics.

I want to do some more stuff with Apricot graphics.

Scheduled Pinned Locked Moved Uncategorized
aprilcot
36 Posts 9 Posters 3 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • bytex64@awesome.gardenB bytex64@awesome.garden

    I wrote a benchmark that tested several different approaches in Turbo Pascal. Everything from a naive implementation using multiplication to hand-tuned assembly. It just pregenerates 10,000 random dots and plots them to the screen using the various methods. The dots on this screen are so fine they almost look like dust.

    I rewrote all my routines to use the new column-based layout and benchmarked it against the old method. And, unsurprisingly, everything is faster! The only one that matters though is the fully optimized Asm2, which is now about 6% faster. Ticks here are DOS ticks, which are hundredths of a second (but because Apricot uses a 50Hz timer, it has a resolution of .02 seconds). So we can now plot ~5K points per second.

    #Aprilcot

    Link Preview ImageLink Preview ImageLink Preview Image
    bytex64@awesome.gardenB This user is from outside of this forum
    bytex64@awesome.gardenB This user is from outside of this forum
    bytex64@awesome.garden
    wrote last edited by
    #3

    Okay, points are fine, but what can we do for actual graphics? As I showed last year, static graphics are not a problem, especially if they're aligned to the 16-pixel character grid. But moving graphics present a challenge. The bits have to be shifted up to 15 positions to work at unaligned locations. If we're okay with using some more memory, we can just do that in advance. Then we just copy whichever is appropriate for the X position.

    bytex64@awesome.gardenB 1 Reply Last reply
    0
    • bytex64@awesome.gardenB bytex64@awesome.garden

      Okay, points are fine, but what can we do for actual graphics? As I showed last year, static graphics are not a problem, especially if they're aligned to the 16-pixel character grid. But moving graphics present a challenge. The bits have to be shifted up to 15 positions to work at unaligned locations. If we're okay with using some more memory, we can just do that in advance. Then we just copy whichever is appropriate for the X position.

      bytex64@awesome.gardenB This user is from outside of this forum
      bytex64@awesome.gardenB This user is from outside of this forum
      bytex64@awesome.garden
      wrote last edited by
      #4

      So here’s some little blob guys bouncing around the screen. 🙂

      #Aprilcot

      bytex64@awesome.gardenB 1 Reply Last reply
      0
      • bytex64@awesome.gardenB bytex64@awesome.garden

        So here’s some little blob guys bouncing around the screen. 🙂

        #Aprilcot

        bytex64@awesome.gardenB This user is from outside of this forum
        bytex64@awesome.gardenB This user is from outside of this forum
        bytex64@awesome.garden
        wrote last edited by
        #5

        Some close-ups so you can see the detail better. These are 16x11 because the pixel ratio on this display is 2:3. I had a hard time finding a pixel editor that would do that odd ratio. Aseprite only does double wide/high. GrafX2 does a lot of them but not 2:3. Turns out GIMP allows effectively arbitrary ratios via per-axis DPI settings.

        #Aprilcot

        Link Preview ImageLink Preview Image
        bytex64@awesome.gardenB 1 Reply Last reply
        0
        • bytex64@awesome.gardenB bytex64@awesome.garden

          Some close-ups so you can see the detail better. These are 16x11 because the pixel ratio on this display is 2:3. I had a hard time finding a pixel editor that would do that odd ratio. Aseprite only does double wide/high. GrafX2 does a lot of them but not 2:3. Turns out GIMP allows effectively arbitrary ratios via per-axis DPI settings.

          #Aprilcot

          Link Preview ImageLink Preview Image
          bytex64@awesome.gardenB This user is from outside of this forum
          bytex64@awesome.gardenB This user is from outside of this forum
          bytex64@awesome.garden
          wrote last edited by
          #6

          Unfortunately, there's no way to synchronize with the screen refresh. The flickering you're seeing isn't a camera artifact, I'm seeing that too. Older revisions had vsync hooked up to one of the PIO lines, but the rev G board I have repurposed that for a serial control signal (gotta love design changes in the same product run).

          And this is an entirely unoptimized routine. Just Turbo Pascal XORing a word at a time into memory. There's a lot of optimization to do, and I'm also hoping I can employ the 8089 at some point. 🙂

          bytex64@awesome.gardenB 1 Reply Last reply
          0
          • bytex64@awesome.gardenB bytex64@awesome.garden

            Unfortunately, there's no way to synchronize with the screen refresh. The flickering you're seeing isn't a camera artifact, I'm seeing that too. Older revisions had vsync hooked up to one of the PIO lines, but the rev G board I have repurposed that for a serial control signal (gotta love design changes in the same product run).

            And this is an entirely unoptimized routine. Just Turbo Pascal XORing a word at a time into memory. There's a lot of optimization to do, and I'm also hoping I can employ the 8089 at some point. 🙂

            bytex64@awesome.gardenB This user is from outside of this forum
            bytex64@awesome.gardenB This user is from outside of this forum
            bytex64@awesome.garden
            wrote last edited by
            #7

            To optimize properly, we must have some way of measuring performance. I’ve set up a handler on the 50Hz timer interrupt that just increments a counter. In the draw loop, I synchronize with that counter, begin drawing, and count how many frames have passed at the end. Then I put that number in the corner of the screen. So if you see zero, all the drawing has completed in one frame.

            I’ve also upgraded to a 32x32 “space invader” that kinda looks like an axolotl. And currently we can draw… one sprite before we blow our frame budget. 😆

            #Aprilcot

            bytex64@awesome.gardenB 1 Reply Last reply
            0
            • bytex64@awesome.gardenB bytex64@awesome.garden

              To optimize properly, we must have some way of measuring performance. I’ve set up a handler on the 50Hz timer interrupt that just increments a counter. In the draw loop, I synchronize with that counter, begin drawing, and count how many frames have passed at the end. Then I put that number in the corner of the screen. So if you see zero, all the drawing has completed in one frame.

              I’ve also upgraded to a 32x32 “space invader” that kinda looks like an axolotl. And currently we can draw… one sprite before we blow our frame budget. 😆

              #Aprilcot

              bytex64@awesome.gardenB This user is from outside of this forum
              bytex64@awesome.gardenB This user is from outside of this forum
              bytex64@awesome.garden
              wrote last edited by
              #8

              Close up on our axolotl invader friend.

              Link Preview Image
              bytex64@awesome.gardenB 2 Replies Last reply
              0
              • bytex64@awesome.gardenB bytex64@awesome.garden

                Close up on our axolotl invader friend.

                Link Preview Image
                bytex64@awesome.gardenB This user is from outside of this forum
                bytex64@awesome.gardenB This user is from outside of this forum
                bytex64@awesome.garden
                wrote last edited by
                #9

                Side note, MAME doesn't emulate this at the same speed. It's almost twice as fast, in fact.

                1 Reply Last reply
                0
                • bytex64@awesome.gardenB bytex64@awesome.garden

                  Close up on our axolotl invader friend.

                  Link Preview Image
                  bytex64@awesome.gardenB This user is from outside of this forum
                  bytex64@awesome.gardenB This user is from outside of this forum
                  bytex64@awesome.garden
                  wrote last edited by
                  #10

                  Well that's not right.

                  Link Preview Image
                  bytex64@awesome.gardenB elithebearded@fed.qaz.redE 2 Replies Last reply
                  0
                  • bytex64@awesome.gardenB bytex64@awesome.garden

                    Well that's not right.

                    Link Preview Image
                    bytex64@awesome.gardenB This user is from outside of this forum
                    bytex64@awesome.gardenB This user is from outside of this forum
                    bytex64@awesome.garden
                    wrote last edited by
                    #11

                    That’s… better. 14 sprites! But obviously not working totally correctly.

                    bytex64@awesome.gardenB 1 Reply Last reply
                    1
                    0
                    • bytex64@awesome.gardenB bytex64@awesome.garden

                      That’s… better. 14 sprites! But obviously not working totally correctly.

                      bytex64@awesome.gardenB This user is from outside of this forum
                      bytex64@awesome.gardenB This user is from outside of this forum
                      bytex64@awesome.garden
                      wrote last edited by
                      #12

                      Well, it's 14 before it starts visibly slowing down. It can actually get to 15 or 16 before the counter increments. This is a hand-written assembly routine. The reason it's leaving trails is because this is using REP MOVSW instead of XOR. And now that I think about it, that means each one is being drawn twice. So that should more than account for any kind of fix to the trails being drawn here.

                      I'm calculating the offset into the array of sprite data (one for each X offset in the character cell) using a regular old MUL, so there' s probably some performance left on the table there. I could precompute those offsets and do a table lookup. Anyway, that's good for tonight.

                      elithebearded@fed.qaz.redE bytex64@awesome.gardenB 2 Replies Last reply
                      0
                      • bytex64@awesome.gardenB bytex64@awesome.garden

                        Well that's not right.

                        Link Preview Image
                        elithebearded@fed.qaz.redE This user is from outside of this forum
                        elithebearded@fed.qaz.redE This user is from outside of this forum
                        elithebearded@fed.qaz.red
                        wrote last edited by
                        #13

                        @bytex64

                        That's winning at solitaire

                        1 Reply Last reply
                        0
                        • bytex64@awesome.gardenB bytex64@awesome.garden

                          Well, it's 14 before it starts visibly slowing down. It can actually get to 15 or 16 before the counter increments. This is a hand-written assembly routine. The reason it's leaving trails is because this is using REP MOVSW instead of XOR. And now that I think about it, that means each one is being drawn twice. So that should more than account for any kind of fix to the trails being drawn here.

                          I'm calculating the offset into the array of sprite data (one for each X offset in the character cell) using a regular old MUL, so there' s probably some performance left on the table there. I could precompute those offsets and do a table lookup. Anyway, that's good for tonight.

                          elithebearded@fed.qaz.redE This user is from outside of this forum
                          elithebearded@fed.qaz.redE This user is from outside of this forum
                          elithebearded@fed.qaz.red
                          wrote last edited by
                          #14

                          @bytex64

                          Is it really a sprite if it's not in hardware? Otherwise it's just sparkling pixels

                          bytex64@awesome.gardenB drj@typo.socialD menos@todon.euM 3 Replies Last reply
                          0
                          • elithebearded@fed.qaz.redE elithebearded@fed.qaz.red

                            @bytex64

                            Is it really a sprite if it's not in hardware? Otherwise it's just sparkling pixels

                            bytex64@awesome.gardenB This user is from outside of this forum
                            bytex64@awesome.gardenB This user is from outside of this forum
                            bytex64@awesome.garden
                            wrote last edited by
                            #15

                            @elithebearded Hah. 🙂 I’d say it’s arguable. The word gets thrown around in a lot of ways to describe everything from the image itself to the particular rendering path.

                            For a particularly confusing example, uxn/Varvara “sprites” are rendered by “hardware” but because it’s an emulation-only platform it’s actually a fixed function software blitter.

                            1 Reply Last reply
                            0
                            • bytex64@awesome.gardenB bytex64@awesome.garden

                              Well, it's 14 before it starts visibly slowing down. It can actually get to 15 or 16 before the counter increments. This is a hand-written assembly routine. The reason it's leaving trails is because this is using REP MOVSW instead of XOR. And now that I think about it, that means each one is being drawn twice. So that should more than account for any kind of fix to the trails being drawn here.

                              I'm calculating the offset into the array of sprite data (one for each X offset in the character cell) using a regular old MUL, so there' s probably some performance left on the table there. I could precompute those offsets and do a table lookup. Anyway, that's good for tonight.

                              bytex64@awesome.gardenB This user is from outside of this forum
                              bytex64@awesome.gardenB This user is from outside of this forum
                              bytex64@awesome.garden
                              wrote last edited by
                              #16

                              17, and no trails!

                              bytex64@awesome.gardenB poetaster@mastodon.gamedev.placeP 2 Replies Last reply
                              0
                              • bytex64@awesome.gardenB bytex64@awesome.garden

                                17, and no trails!

                                bytex64@awesome.gardenB This user is from outside of this forum
                                bytex64@awesome.gardenB This user is from outside of this forum
                                bytex64@awesome.garden
                                wrote last edited by
                                #17

                                This has the pointer table optimization (every shifted version of the sprite is pointed to from a table instead of being calculated via MUL). I created a whole second routine to blank sprites, which is the same thing except it does STOSW instead MOVSW. It took me longer to get that working than the sprite draw routine because I misunderstood the documentation. I thought it referenced DS for the target and not ES because Intel's manual didn't specify either.

                                This is still a very bad draw routine because it just overwrites the entire 16-pixel word instead of doing proper masking. That'll probably drop the performance by 30% because it can't use the 8086's fast string instructions.

                                tursilion@furries.clubT bytex64@awesome.gardenB 2 Replies Last reply
                                0
                                • bytex64@awesome.gardenB bytex64@awesome.garden

                                  This has the pointer table optimization (every shifted version of the sprite is pointed to from a table instead of being calculated via MUL). I created a whole second routine to blank sprites, which is the same thing except it does STOSW instead MOVSW. It took me longer to get that working than the sprite draw routine because I misunderstood the documentation. I thought it referenced DS for the target and not ES because Intel's manual didn't specify either.

                                  This is still a very bad draw routine because it just overwrites the entire 16-pixel word instead of doing proper masking. That'll probably drop the performance by 30% because it can't use the 8086's fast string instructions.

                                  tursilion@furries.clubT This user is from outside of this forum
                                  tursilion@furries.clubT This user is from outside of this forum
                                  tursilion@furries.club
                                  wrote last edited by
                                  #18

                                  @bytex64 What if you used the old Apple2 trick of XORing the sprites instead. Gives you draw and erase without destroying the background (at the cost of some corruption, but it's generally ignorable 🙂 )

                                  bytex64@awesome.gardenB 1 Reply Last reply
                                  0
                                  • tursilion@furries.clubT tursilion@furries.club

                                    @bytex64 What if you used the old Apple2 trick of XORing the sprites instead. Gives you draw and erase without destroying the background (at the cost of some corruption, but it's generally ignorable 🙂 )

                                    bytex64@awesome.gardenB This user is from outside of this forum
                                    bytex64@awesome.gardenB This user is from outside of this forum
                                    bytex64@awesome.garden
                                    wrote last edited by
                                    #19

                                    @tursilion That’s what I did initially in the naive version. It does work, but it also can’t take advantage of REP STOSW for fast copies, so it’ll be slower.

                                    1 Reply Last reply
                                    0
                                    • bytex64@awesome.gardenB bytex64@awesome.garden

                                      17, and no trails!

                                      poetaster@mastodon.gamedev.placeP This user is from outside of this forum
                                      poetaster@mastodon.gamedev.placeP This user is from outside of this forum
                                      poetaster@mastodon.gamedev.place
                                      wrote last edited by
                                      #20

                                      @bytex64 exceedingky cute axoloinvaders!

                                      1 Reply Last reply
                                      0
                                      • bytex64@awesome.gardenB bytex64@awesome.garden

                                        This has the pointer table optimization (every shifted version of the sprite is pointed to from a table instead of being calculated via MUL). I created a whole second routine to blank sprites, which is the same thing except it does STOSW instead MOVSW. It took me longer to get that working than the sprite draw routine because I misunderstood the documentation. I thought it referenced DS for the target and not ES because Intel's manual didn't specify either.

                                        This is still a very bad draw routine because it just overwrites the entire 16-pixel word instead of doing proper masking. That'll probably drop the performance by 30% because it can't use the 8086's fast string instructions.

                                        bytex64@awesome.gardenB This user is from outside of this forum
                                        bytex64@awesome.gardenB This user is from outside of this forum
                                        bytex64@awesome.garden
                                        wrote last edited by
                                        #21

                                        We've maxed out the CPU, but the Apricot has another trick - the 8089. It's a dedicated I/O coprocessor, and theoretically it can push bytes even faster than the CPU. If... I can get it working.

                                        I've discovered the hard way that Turbo Pascal is really picky about what it can link with. It _only_ wants to link with external functions. If the OBJ file you're linking with has _any_ data segment symbols, it flat out refuses to deal with it. At first I thought this was a subtle bug in how asm89 generates OMF files, but it does the same with a C file compiled with Turbo C. And since asm89 defines the 8089 machine code symbols as data (which I think is correct from the POV of the CPU), it just doesn't work. 😕

                                        So I guess I'll just have to copy the machine code into the Pascal source as raw data. That sucks.

                                        #Aprilcot

                                        bytex64@awesome.gardenB 1 Reply Last reply
                                        0
                                        • bytex64@awesome.gardenB bytex64@awesome.garden

                                          We've maxed out the CPU, but the Apricot has another trick - the 8089. It's a dedicated I/O coprocessor, and theoretically it can push bytes even faster than the CPU. If... I can get it working.

                                          I've discovered the hard way that Turbo Pascal is really picky about what it can link with. It _only_ wants to link with external functions. If the OBJ file you're linking with has _any_ data segment symbols, it flat out refuses to deal with it. At first I thought this was a subtle bug in how asm89 generates OMF files, but it does the same with a C file compiled with Turbo C. And since asm89 defines the 8089 machine code symbols as data (which I think is correct from the POV of the CPU), it just doesn't work. 😕

                                          So I guess I'll just have to copy the machine code into the Pascal source as raw data. That sucks.

                                          #Aprilcot

                                          bytex64@awesome.gardenB This user is from outside of this forum
                                          bytex64@awesome.gardenB This user is from outside of this forum
                                          bytex64@awesome.garden
                                          wrote last edited by
                                          #22

                                          But anyway, with that worked around, invoking the 8089 from Pascal seems to work. The code here is very simple:

                                          MOVI GA, 1
                                          ADD [PP].4, GA
                                          HLT

                                          It just adds 1 to the word at offset 4 in the parameter block. The first two words point to the code itself, so the third one is where parameters live. The Pascal code that invokes it just sets that to 0, and the output below shows that it has been changed, and then dumps the state of the 8089 Channel Control Block.

                                          #Aprilcot

                                          Link Preview Image
                                          bytex64@awesome.gardenB 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups