Oldskooler Ramblings

the unlikely child born of the home computer wars

Best In Class

Posted by Trixter on January 4, 2015

Sanity wrote something in their Arte end-scroller that always stuck with me:  If you can’t do it better, why do it?

This was my hobby philosophy for over two decades.  It’s the philosophy that created all of the demoscene productions that I am known for, such as 8088 Domination; I’ve placed 3rd or higher in every competition I’ve entered.  It was what fueled my involvement in the Abandonware concept, which would likely have died on the vine without the search engine I created for the original Abandonware Ring (this was in the days before Google and RSS existed; without a search facility, it was cumbersome to find games).  It was what prompted me to design and implement MobyGames with my friend Brian Hirt (several years before wikipedia existed).  It created the MindCandy series of DVDs and Blu-rays.  I am proud of all these accomplishments.

This was my hobby philosophy.

I’m stepping down from always trying to be the best at what I do.  The primary reason is to preserve my sanity, as I am haunted by mistakes I’ve made.  At least one night a week, I lay awake unable to stop thinking about them.  Plus, it contributes to an unhealthy obsession (which also keeps me awake) over trying to be the very best I can be in my various hobby pursuits.  I can’t keep assigning self-worth to project success.  It both paralyzes me and tears me apart.

There was a time when I thought I needed my hobbies to deal with life and stay sane.  Today, I’m finally realizing that all of the successful accomplishments in my life were achieved when I was simply relaxing and having fun.  So that’s what I’m going to do — have some fun and work on what I want to work on, rather than try to win competitions and impress people in my various circles.  If I get another minute of fame along the way, then that’s a nice bonus, but it’s not the goal.

So what’s next?  What is “fun”?

  • More blog posts.  I enjoy writing, even if nobody enjoys reading what I write :-)  Maybe someday my kids will find this blog and get a better sense of what their father was like.
  • S00p3r sekr3t demo project.  See you at Revision!  Hint: It’s not a solo production.  Hint #2: I am the worst coder in the group — that scares me tremendously, and it should scare you too.
  • S00p3r sekr3t vintage gaming project.  Think big!
  • Personal Computer Sound Museum.  This has been in the works for ten years.  Unless there are complications, this will be implemented in Drupal 8 because I need a functional taxonomy framework and Drupal seems to be the only CMS that has one.  So, when Drupal 8 is out of beta, I’ll start tinkering.
  • A vintage computing audio podcast, time permitting.

Most importantly, I hope to make my family and friends laugh this year.

Posted in Lifehacks | 9 Comments »

CGADEMO by Codeblasters

Posted by Trixter on November 22, 2014

I don’t normally reblog other people’s blogs, but my own blog has been neglected lately due to work on other vintage computing and programming projects, so I thought I would share a post by my friend Scali that covers a vintage programming problem just as well, if not better, then I would have covered. Enjoy.

Scali's avatarScali's OpenBlog™

Today I want to talk about a rather obscure, yet interesting demo, namely CGADEMO by Codeblasters, from 1992:

As you can read from the scroller, what’s interesting about this demo is that it runs at full framerate (60 Hz) even on the original IBM PC (8088 at 4.77 MHz with CGA). And that there are 16 colours on screen at the same time.

Unstable rasters

To start with the 16 colours… They use a trick similar to my palette switching in the 1991 donut. Namely, they change the background colour of the CGA palette at every scanline, which gives a rasterbar effect. This is very similar to what I have discussed on C64. This demo does not use a stable raster however, since that is very difficult to achieve on a PC anyway. Instead, they use polling of the hblank status bit to determine when a scanline is…

View original post 1,454 more words

Posted in Uncategorized | Leave a Comment »

Fun for the feeble-minded

Posted by Trixter on October 26, 2014

As a teenager in the 1980s, I loved using computers, and also building things, and especially loved building things with computers.  Naturally, I adored Music Construction Set and Pinball Construction Set.  The version of Music Construction Set for the PC floating around in the wild was mine; it comes with 30+ tunes more than the original diskette had, mostly covers as I learned to use the program, or learned my music lessons, or transcribed tunes I heard on other computers (the “power bots” MCS tune should be familiar to Apple II owners).  My Pinball Construction Set tables were not as enjoyable, so they stayed with me.

The more I built my own tables, the more I wanted to see how other tables were built.  I acquired a copy of Night Mission Pinball from a friend, and played it for hours, jealous of how much more it did than PCS:  Sound was more “authentic”, more complicated scoring, better graphics.  I ended up playing it exclusively and stopped using PCS.

Unfortunately, I played it so much that the disk wore out and wouldn’t boot any more.  Worse, my friend no longer had a copy to make for me, and I was too broke to buy it proper.  What to do?

Build my own in Pinball Construction Set, obviously:

mynight_000

I did this from memory just from playing the original game for so many hours.  It’s not perfect, but when you compare it to the original, I think I did a pretty good job:

pinball_000

If you’d like to play the amateur horror that is Jim Leonard’s Night Mission Pinball, you can now do so.

Posted in Gaming, Vintage Computing | 1 Comment »

An Episode Guide to Monsters (The TV Show)

Posted by Trixter on October 11, 2014

The 1980s was defined by trends, one of which was the rise of the classic horror movie.  This manifested itself in the form of several “horror” TV shows that combined elements of The Twilight Zone (including a Twilight Zone remake itself!), A Nightmare On Elm Street, and elements of traditional horror.  These were sometimes hard shows to make, as they had to be sufficiently scary, disturbing, surprising, etc. while not violating any television broadcasting codes.  Many episodes used humor to disarm some of the more unsettling themes.  Due to the content, many of these shows were broadcast only in the late evening between midnight and 2am.

Two of these horror anthologies, Tales from the Darkside and later Monsters, were produced by Laurel Entertainment, the brainchild of George Romero and Richard P. Rubinstein.  Tales was pitched to networks based on the success of Laurel’s Creepshow, which WGN bought and syndicated.  When it ended, Laurel started Monsters.  Monsters is very much like Tales, except it focuses more on horror, whereas Tales delved into sci-fi, fantasy, and modern-day “ironic twist” stories similar to The Twilight Zone.

Being the month of Halloween, there’s no better time to check out Monsters.  It was recently released on DVD, and you can find the entire series online if you look hard enough.  To help you experience only the good stuff and skip terrible episodes, I’ve created Trixter’s Totally Subjective and Spoiler-free Guide to Monsters (The TV Show).  It’s presented as a Google Docs spreadsheet with some filters for your convenience.

By “spoiler-free”, I mean I’ve created a column that describes the basic plot of the show without giving away anything that would ruin any surprises, twist endings, etc.  If you want to only check out notable guest stars, there is a “notable guest stars” column.  If you are only watching Monsters because you were a fan of Tales from the Darkside, there is a column for that too: Because both shows were created by the same production company and most of the same people, many Monsters episodes feel more like TFTD, so you can filter on that if you were only a fan of the former.

But if you’re really short on time, just use the filter on the Grade column and watch anything graded A.  Some of those are just bananas.

Posted in Entertainment | Tagged: , , | 1 Comment »

The Outlandish Adventure of Miss Amanda Collins

Posted by Trixter on October 7, 2014

In the world of vintage computing history and preservation, I am both an archivist and a conservator.  There are very many archivists in various corners of our field; it is easy to gather up collections from multiple sources and dump them in a single place for the viewing public.  Conservators, however, are the people who roll up their sleeves and get their hands dirty.  They perform the task of extracting the archival works in the first place from the original distribution medium.  This can range from reading files off of a disk, to reconstructing long-past systems using 3-D printed replacement parts, to figuring out the structure of unfamiliar data.  Conservation is work.  Our hobby needs more conservators.

Some data rescues have high visibility, such as the recovery of Andy Warhol’s early digital art.  But the majority of rescues are not notable.  My specific area of focus is very early (think 1980s) PC games on floppy disks, and recently I’ve recovered a few items not yet found “in the wild”, but painfully boring:  A horrible WWII flight combat sim, a chess tutor, a children’s A-B-C program.  The latter is PCjr-specific, which is intriguing, but for the most part these items hold no significant place in history.  Still, I do it for The Cause.

One enjoyable side benefit of this work is occasionally coming across something human amongst the digital clutter.  Like a trunk discovered in an attic that hasn’t been opened in decades, you can find all sorts of clues about a person’s or family’s past, pieces of their lives, hiding in the data: Letters to family, ledgers and receipts, creative writing, favorite recipes, comic book collections, a child’s digital fingerpainting.  I’ve found these and more during my archaeology, and it always makes me smile.  (Please don’t get the wrong idea; I don’t mean the above to sound voyeuristic, but rather more of admiration and respect for the original owners who actually used their systems to improve their lives.)

One favorite example in recent memory was when I rescued a no-name taiwanese XT clone out of the trash (literally; it was in a dumpster).  Based on the files left behind, the system was owned by an asian female college student in the late 1980s who was an accounting major and used the computer exclusively for school… or so it looked at first glance.  Tucked away among all of the spreadsheets, essays, and databases, in a tiny corner of the filesystem, was a single directory that was filled with poetry, in a style written with few carefully and powerfully chosen words.  The entire system and its files gave the impression of a young woman who was following her father’s wishes, but who longed for something more fulfilling.

And it is here I will introduce you to miss Amanda Collins, who holds the record for the most endearing recovery I’ve had this decade.  I don’t know anything about her other than her name, and I certainly don’t know which out of the nearly 1500 “Amanda Collins” located in the USA White Pages she is.  I don’t know how old she is (although I have a good guess how old she was). All I can tell you is how I found her.

I was going through disks to archive and found a commercial business program from the early 1980s that looked interesting; I had never run across it before, and it was copy-protected which is always a fun challenge.  But more interesting is that it was sticky.  As in, peanut butter and jelly sticky — on the media itself (ie. the part that shows in the “window” that the diskette sleeve’s pictographs illustrated you were never, ever supposed to touch).  Rescuing this disk required actual warm water, a soft cloth, and careful rubbing.  Unfortunately, the diskette had been permanently damaged by whatever had stuck to the media, but I figured I’d work a little harder on the first few tracks just so I could see what was on the disk and call it a day.  At the end of the directory, after the commercial program files, was a file called ET with no date on it.  I wasn’t able to rescue the program, but I was able to get the ET file.  It is my pleasure to share it with you exactly as I found it:

ONE DAY I WAS WALKING DOWN THE STRET 
AND SAW E.T. HE REPLIED WHO ARE YOU.
I REPLIED I AM AMANDA N. COLLINS. 
SO WE WENT WALKING THEN E.T AND I 
WENT TO MARY'S SHE SAID WHAT A CUTE 
 CREATRUER I SAID IT IS E.T WHAT? 
REALY.IAM NOT JOKING.THEN PROVE IT TO 
ME OK E.T. GIVE ME YOUR FINGER LIKE YOU
DID IN THE MOVIES E.T REPLIED OK. MARY
SAID I DON'T BELEAVE  IT.  E.T AND I 
SAID BYE-BYE MARY SAID  OK GOOD BYE.
 THEN I WENT TO RICK'S HOUSE HE SAID
GEEPRES E.T.  I'LL BYE HIM OFF YOU 
FOR 50$ I SAID SORRY BUT HE IS NOT FOR
 SALE  AMANDA  50$ PRACTICEL IT IS NOT
PRACTICEL  THEN  IF 50$ IS PRACTICEL 
THEN HOW ABOUT  2.00$ COME OFF IT RICK
THEN 5.000$ NO-ON-NO STOP POOLING MY
HAIR NOT UNTIL YOU LET ME HAVE HIM.RICK 
I'VE GOT A IDEA I WILL HAVE HIM FOR SIX
MONTHS AND YOU WILL HAVE HIM FOR SIX
MONTHSRICK AGREED  AND THERE WAS NO MORE
FIGHTING ANYMORE BETWEEN RICK AND I SO 
E.T AND I WENT TO BERGER KING E.T ORDER
A CHEESE BERGER AND A HAM BERGER WITH 
EXTA ONIONS AND PICLES E.T. ALSO ORDER
A LARGE ORDER OF FRENCE FRIES.THEN WE
WENT TO MY HOUSE I HIDE E.T IN MY BARBE
HOUSE WHEN MY MOTHER WENT TO CLEANE MY
BARBE HOUSE SHE YELLED AMANDA GET DOWN
HERE AMEIDLE .I SAID WHAT IS WRONG
AMANDA STOP JOKING MOM REALY I DON'T
KNOW WHAT YOUR TALKING ABOUT THEN 
EXPLAIN THIS  E.T.GET HIM OUT OF HERE.
NOW IS MY ONLY CHACNE TO GET IN ONE OF
MY DOLLS   DRESSES AND HIDE HIM IN MY
CLOSET . WHEN MOM CAME TO CHECK MY 
CLOSET MOM SAID WHERE DID YOU GET THAT
NEW DOLL .I SAID I SENT AWAY FOR IT .GO
AHEAD BUT NOT NEXT TIME I'LL REMEMBER.
THEN WE WENT OUT FOR BREAKFAST.WE WENT
TO MC DONALD'S WE HAD PANCAKES OFF THE
OVEN THEY WHERE SHORE GOOD.E.T.SAID
LET'S GO  TO THE MUSEMS I SAID LET'S GO
SEE THE DINASORES. THEN WE WENT TO THE
PARK AND THEN BACK TO MC DONALD'S AND
HAD LUNCH AT 7.45 WE CAME TO A END AND
HAD DINNER AT 8.04 AT 12.55 E.T AND I
WENT TO BED.
                   THE END.
                      BY
                        AMANDA  COLLINS

This little girl had decided one day to write a story, and when the program prompted for a diskette to save it, she grabbed — with sticky jelly fingers — whatever diskette was closest and jammed it in… in this case, Daddy’s expensive business program, ruining it in the process, and possibly the drive it was jammed into.

I lack the skill to convey how adorable I find this.

In your own digital archaeology adventures, may you someday feast on cheese bergers, and see dinasores at the park.

Posted in Vintage Computing | 1 Comment »

Cyberpunx

Posted by Trixter on October 5, 2014

October is “National Cyber Security Awareness Month”, whatever the hell that means.  In recognition of this dubious designation, I’ve made an HD remaster of the 1990 documentary Cyberpunk available.  Consisting of interviews with William Gibson, Jaron Lanier, Timothy Leary, Vernon Reid (from Living Color), and Michael Synergy, and briefly featuring a few industrial bands such as Front 242, Manufacture, and Front Line Assembly, the documentary provides a look at what the cyberpunk movement was circa 1990.  Subjects such as cyber-terrorism, cybernetic implants/enhancement, virtual reality/telepresence, and general counterculture rebellion against “The System” are touched upon.  Inevitable comparisons with Akira are made.

Here Be Dragons

While the producer and director did an admirable job making the source material interesting and presentable to the public, there are a lot of flaws with the documentary.  Some are minor and can be overlooked, such as the 1990s trend of inserting faux computer graphic overlays (to try to make the material more similar to the world Gibson painted in Neuromancer).  Many of the problems are with pacing; there are entire sections that focus on a particular subject for too long, sometimes without impact.  One section in particular goes so long that different digital effects start to fade in and out after a few minutes, almost as if the editor was bored and resorted to doing something with the image to keep the viewer’s interest.

There are also some very misrepresented facts and predictions, but it’s not really fair to criticize a documentary for failing to predict the future correctly.  That being said, there are some real howlers in here, from the supposed power hackers wield(ed) against governments, to the silly, amateur computer graphics that obscure hackers’ identities, to the heavily hinted-at concept that Neuromancer itself was responsible for shaping technology and history.  The most egregious is equating hacker with cracker (although, to be fair, that’s happened multiple times before and since).

A special mention must be given to Michael Synergy, who perfectly embodies the huckster who started believing his own bullshit.  Some of his claims in the documentary are so utterly, patently ridiculous, so incredibly pretentious, that it takes a great deal of willpower not to scream at him when he’s talking (especially when he mispronounces the word “genre”).  Were I him, I would have wanted this stage in my life to disappear, and it seems as if that wish has come true: His moniker disappeared with the 1990s.  My personal wild speculation is that once the real, actual revolution of the web occurred and it was able to finally call him out, he quietly exited stage left.  (Last I heard, he worked for Autodesk in the mid-1990s, was going by his birth name again, living in Hawaii, working in IT; if anyone has a real update, I would love to know what actually happened to him.)

Most depressingly, there is a real missed opportunity with how Jaron Lanier’s involvement was portrayed.  In the documentary, he comes across as a stoner who only mentions VR, which is a shame because — then and now — he’s the most relevant and accurate representation of a hacker that the documentary includes.  Of everybody interviewed, Jaron is the only person who is still exploring these concepts and ideas, and more importantly their unintended fallout, which you can read about in his most recent book Who Owns The Future?.  (Even if you don’t buy the book, follow that link and read the Q&A to get a feeling for his concerns.)

Worth watching?

While it may be hard to sit through, the documentary retains glimpses of the innocent, wildly-optimistic, techno-hippie idealism that grew with the rise of personal computing and networking.  For that nostalgia factor alone — the time when the Internet existed but the World-Wide Web did not — it’s worth an hour of your time.  It’s also worth watching to catch which ideas were especially prescient, such as:

  • Whoever holds the most information holds the most power
  • Every device will be interconnected
  • Physical boundaries will not impede meaningful communication
  • People will be individual, mobile, uncensored “broadcast stations” (considering I can post to youtube from my phone, I’d call this a reality)
  • The “matrix” as a concept and/or allegory for God (later realized almost to the letter in The Matrix movie trilogy)

…and so on.  You could make an interesting drinking game out of catching which ideas succeeded (although you’d get more drunk, quickly, by catching all of the stupid and inaccurate comments).

Cyberpunk: The Documentary is now available at archive.org.  Grab the MPEG-TS file if able; it’s 60p, Blu-ray compliant, and won’t take up too much space in your memory implant.

Posted in Digital Video, Entertainment, Technology | Tagged: , | 2 Comments »

Two decades of “the demoscene on the web”

Posted by Trixter on September 29, 2014

This month marks the two-decade anniversary of me putting the first pages on the web describing what the demoscene was.  No need for the wayback machine; the pages are still up and running, of sorts.  Horribly outdated by today’s standards, obviously; you can get more and better information from wikipedia (until they decide to completely erase the demoscene as being not notable, of course).  But it was current enough a year later to get me interviewed for a Wired magazine article on the demoscene, which was cool at the time.

Those were the days when you learned how to write HTML by looking at the source of other pages.  I’m writing this post in a fully AJAX editor that is probably written completely in javascript — I’m not sure, as I’m too afraid to look under the hood for fear of burning my retinas out.

Posted in Demoscene | 2 Comments »

8088 Domination Source and Encoder Released

Posted by Trixter on August 11, 2014

I’ve formally released the source and binaries for the 8088 Domination encoding system under its original working title: XDC (stands for X86 Delta Compiler).  Head on over to x86dc.wordpress.com to browse the github source, grab some example videos, browse the documentation, or watch a screencast where I encode a video from farm to table in under 30 minutes.

Now you too can impress your friends with your own custom videos that run on a 4.77 MHz CPU with 16K of video memory!

Posted in Demoscene, Digital Video, Programming, Vintage Computing | Leave a Comment »

Out, damned bug! out, I say!

Posted by Trixter on July 29, 2014

The response to 8088 Domination was warm, wonderful, and widespread. To everyone who dropped me a note via twitter, email, or youtube — and there were thousands of you — I want to thank you for the kind and encouraging words.

Even before I finished the design, I knew that I was going to release all of the source, so that others could make their own videos for their own vintage systems. I was careful to design the system to be easy to understand, so that it could be easy to port to other languages or extend with new features. I have a lot of comments in the code, some fairly verbose, so that there is no confusion why something is designed a particular way, or why one operation happens before another. I want this to be representative of the quality of code I usually write.

So, why am I overdue in releasing the code? Bugs! Or, more accurately, edge cases. To ensure that the encoder works properly in the real world, I’ve been testing it with vastly different sources: Animations, music videos, cartoons, even a full-length movie. And almost every time, I encounter a new edge case that needs fixing. Oh, don’t worry — The code isn’t full of special cases or bubblegum-and-shoestring workarounds. It just takes time to address each issue that crops up, and determine if it’s a true bug that needs fixing, or an issue that can be safely ignored.

“Ignore issues in code? Impossabru!” Actually, here’s an example of what I mean: I discovered a few weeks ago that I could improve the efficiency of the output a few percent by re-running some optimization phases before final compilation. However, doing this will sometimes create a small “empty” 1-byte delta that actually isn’t a delta (ie. the locations contains the same data in the previous and next video frames). It’s a bug, but is it worth fixing? I could spend days rewriting the optimization phase into a gigantic, monolithic procedure where all parts coordinate… or, I can throw these 1-byte non-changes away at the end of the existing optimization phase. You can guess which path I chose.

Some bugs are indeed bugs, and they must be fixed before I put my name on the code. For example, the bug that forced the encoding loop into a deadlock, or the bug that randomly produces black flashes in the output (still working on this one), or the bug whose generated code forgot to set a single register which prevented videos from being played without a soundcard present.

So, I hope everyone understands why the code release is late. Well… one of the reasons it is late. The other reason is that making your own videos will require some documentation (some user-directed preprocessing of the source video is necessary — sorry!), and a video showing the steps involved couldn’t hurt either, so that will require a few days by itself.

While you’re waiting, why not help me decide what movie to convert and release with the final distribution? In keeping with the spirit of the time period, I’m going to convert an entire full-length movie using the system, and ensure that it will fit onto a single CD-ROM so that users without homebrew XTIDE controllers can hook up a SCSI CDROM drive and enjoy the flick (ironically). The defacto example for this kind of thing is Star Wars, although I’m partial to TRON, as it was released after the IBM PC itself was and has its own share of iconic sequences. But, I’ve already done TRON to death, so what would you like to see? Vote in this handy poll, and if the movie you want to see isn’t there, please write your choice in the comments.

Posted in Demoscene, Digital Video, Entertainment, Programming, Vintage Computing | 6 Comments »

8088 Domination Post-Mortem, Conclusion

Posted by Trixter on June 20, 2014

This is the second (and last) part of my write-up on how 8088 Domination was achieved; the first part is here. I reuse some terminology introduced in the first part, so before we continue, it’s worth reviewing some key definitions to avoid confusion:

Delta: An area of bytes that needs to change in screen memory to update the displayed image
Slice: A delta where not all bytes are the same value
Run: A delta where all bytes are the same value

On to the nitty-gritty!

Breaking With Tradition

If you’ve coded video or animation systems in the past, you may have correctly identified what I’m doing as less of a video codec and more of an animation system. Animation systems from the 1980s such as Autodesk Animator or DeluxePaint Animation store and play back deltas by iterating through data that describe what areas of screen memory to change, using codes and chunk types for things like “skip N pixels forward, then change M pixels”, “fill entire screen to solid color N”, and so on. This reduces the size of the file, but requires some decision-making and branching while iterating through the data.

I initially did the same thing, and wrote a fast routine that would iterate through a list of deltas to replay, handling runs using the efficient REP STOSB sequence, and the rest with REP MOVSB. It looked something like this:

Delta format:
0-1: start offset
2:   length in upper 7 bits and run/slice in LSB. If set, is run.
3:   fill value (if run; unused if slice)
4-N: data (if slice)

Decompressed via:
; Prior setup:
; DS:SI=source data
; ES = destination (screen RAM)
; DX = number of deltas to iterate through

@loopit:
    lodsw       ;load offset
    xchg di,ax  ;get destination ready
    lodsw       ;load bit, length, value
    shr ah,1    ;isolate LSB?
    mov cl,ah   ;move length into place
    jc @run     ;if so, it's a run
                ;runs are the exception; slices should fall though first
@slice:
    rep movsb   ;copy slice to screen
    ;okay to fall through here since cx=0, rep stosb will do nothing
@run:
    rep stosb   ;replay run to screen (AL already has value)
@continue:
    dec dx
    jnz @loopit

This is optimal 8088 code for this operation, but the idea has two problems. First is a minor annoyance; a byte is wasted storing a fill value even if we aren’t handling a run. But the real problem is that there are two branches (JC and JNZ) for every delta we iterate over in the list. Branches are costly on almost all CPUs, even those as old as the 8088. This was a huge concern for me, as the average new image in my test material was made up of roughly 600 deltas, most of them slices. Some quick math to illustrate why this concerned me:

# of cycles available to us to paint a frame: About 40,000
# of cycles taken up by one untaken (JC) and one taken (JNZ) branch: About 24
# of cycles used by branches to replay 600 deltas: 14,400 (36% of our total)

So, in a typical frame full of changes, more than a third of our available CPU time is wasted handling branches. In a system where we have the same time quantum as 8088 Corruption but are trying to change more data than it did, this was a big step in the wrong direction!

I thought of a few ways to mitigate this cost, such as unrolling the loop, rearranging deltas so that slices and runs are grouped together, and so on. This went on for about an hour before inspiration struck: Why not eliminate the branches altogether?

And just how the hell do you do that? By generating code instead of data. Instead of having the encoder spit out a description of what changes need to be made each frame, we switch to generating x86 opcodes that, when executed, directly implement the changes themselves.

This is the same strategy used to accelerate sprite plotting on many architectures, but when I realized I’d be doing the same thing for the entire screen, I started laughing out loud. What a ludicrous idea! And yet, in practice, you can see that it works.

It’s A Compiler!

The basic structure of a video “code” frame looks like this:

Startup code: Sets ES to point to the screen and DS:SI to point somewhere below its own instruction stream to where the data stream starts
Instruction stream: Instructions that re-point DI to new screen memory destinations and then issue combinations of MOV, MOVSB, STOSB, REP MOVSB, or REP STOSB to change screen memory contents
Cleanup code: A single RETF instruction to return to the caller
Data stream: For (REP) MOVSB, data that gets moved to areas of screen memory

As long as the code is aligned to a DOS 16-bit paragraph boundary, it will execute properly, so the player code enforces alignment of the frame data to paragraph boundaries. Not doing so results in hilarity, as the correct screen memory locations will be changed properly, but with data from the wrong place:

This is supposed to be an anime girl, not digital vomit

This is supposed to be an anime girl, not digital vomit

(It is, of course, quite possible to rewrite a few values in the code to get it to execute properly wherever it is located, but I didn’t want to perform code fixups realtime at 60hz — the system is already slow, let’s not make it any slower.)

Because the instruction stream adds size and processing time to the video data, it’s important for us to generate optimal code that is as fast as possible without being too large. For example, if you want to set a single byte in an arbitrary location pointed to by ES:, most x86 asm programmers would do it like this:

ES: MOV BYTE PTR [nnnn],val

This is fast and is 5 bytes in size. But if you have your value pointed to by DS:SI, you can also do it like this:

MOV DI,nnnn
MOVSB

This is also 5 bytes (4 opcode, 1 data) but is slightly slower… but because MOVSB advances DI automatically, it can save you from having to do the same thing manually. For a single byte it’s not a win, but what if we have three bytes to change? We can continue to set them directly:

ES: MOV WORD PTR [nnnn],mmmm
ES: MOV BYTE PTR [nnnn],mm

…or do this instead:

MOV DI,nnnn
MOVSW
MOVSB

The latter method is much smaller and slightly faster. (This can go on for a while, but eventually there is a break-even point where switching to REP MOVSB is faster than all other encodings.)

Although I had worked out most optimal combinations for various slice and run durations, in the end I felt it was better to just have the compiler generate every code variation, calculate how many cycles each one took to execute, and pick the fastest one. (I figured it was safer and more future-proof than me trying to hand-optimize generator output.) Calculating cycle counts for the 8088 is almost as easy as it is for 8-bit CPUs; the 8088 has only one core, no cache, no threads, no pipelines, no out-of-order execution… it does have a prefetch queue, but it is only 4 bytes long so it isn’t very effective. The major factor in optimizing 8088 code for speed is minimizing memory accesses, because the CPU takes 4 cycles to read (or write) a byte — any byte, even instruction stream opcodes. So, in most cases, the smallest code usually wins. The only exceptions to this rule are instructions that take an extremely long time, such as MUL/DIV, which can run for over 100 cycles depending on the operands.

Andrew Jenner, a good friend and a better coder than I am, has an excellent rule of thumb for determining 8088 code execution speed: Multiply the size of the opcode and the size of any data touched by that opcode by 4 for an informal cycle count; then, also determine the sum of each instruction’s published cycle count. Whichever number is larger is the more accurate execution time estimate.

I won’t go over the code generator itself in this write-up because it is very mundane and not terribly exciting; refer to the source code when I release it in a few weeks.

Delta Optimizations

Once I had an idea of the code generation cost, I came up with a couple of ways to reduce that cost by manipulating the delta list before it was processed by the encoder. Less work for the compiler to do meant smaller code/data and faster execution. Delta optimization consists of four phases:

  1. Run Identification and Splitting. Because runs process faster and encode much smaller than slices, it is a huge win to identify any runs hiding inside of slices and split them out into their own delta. This phase also marks any runs it finds as excluded from further processing (“frozen”), as runs are already optimal.
  2. Pixel “Shaving”. Changing only a single byte in screen memory has a very high cost (5 opcode bytes, plus the time they take to execute) so pixel “shaving” looks at each single-byte delta to determine how many pixels are actually changed by the byte. If a particular threshold is not met (ie. “more than one pixel”), the delta is dropped completely. This is a user-configurable option and is off by default.
  3. Delta “Shaving”. Identical to pixel shaving, except entire deltas are dropped if they aren’t large enough. The default threshold is “more than two bytes”; anything smaller is dropped. This is also user-configurable, and also off by default.
  4. Delta Combination. This phase looks for deltas that are spatially close to each other in linear memory and combines them together if the end result would encode as less bytes. For example, assume we have three 1-byte deltas all spaced one byte apart. Also assume that replaying these three deltas costs 5 bytes each, for a total of 15. Now consider what happens if we combine all three deltas into a single delta spanning the three changed bytes: The number of bytes changed onscreen will grow by 2, but we shed 10 bytes because we only have one delta to set up and replay. It is a net win, so it is always worth it to try to find combination opportunities. (This is technically an NP-hard problem, and implementing it quickly and stupidly as an exhaustive search greatly slowed down the code. I optimized it by re-sorting the deltas by start offset, so that the search space is localized around the delta(s) being examined. After all the combinations are found, the deltas are re-sorted back into the order that assists the encoding phase, as described earlier in part 1.)

All of these phases reduce size and execution cost. The pixel shaving and delta shaving phases have the added benefit of cleaning up the source video a little; if a pixel is “shimmering” over time due to being right at the error threshold of the dithering process, it will be “stable” with pixel or delta shaving turned on. The drawback to the shaving phases, however, is that the output can leave “trails” onscreen as smaller changes are never fully cleaned up or overwritten. Use with caution.

(While not benefiting optimization, there is also a prep phase that executes before the other phases and performs oversize delta splitting, which takes deltas that are too large to execute within our available cycle pool and breaks them up into smaller deltas. This is always necessary when the entire screen changes, as this creates a delta list that consists of only one single delta with a start offset of zero and an end offset at the edge of screen memory. A delta that big is way over both the available byte and cycle limits, so it has to be split into smaller chunks to be replayed over multiple passes.)

Playing With Variable Packets

The player for the 8088 Domination FMV data is very similar to 8088 Corruption: By controlling the size of the audio data the soundcard interrupt handles, we can get the interrupt to fire at our desired video framerate and use the opportunity to update the video as well. The interrupt handler pulls data out of a queue and updates the screen at the same time it updates the audio. While the interrupt is firing in the background, a foreground loop is constantly reading from disk and putting data into a queue. I cover this in more detail in 8088 Corruption Explained, so if you have a half hour to kill, I highly recommend snagging the MPEG-2 file (best quality) and watching it.

Where the players differ, however is in two areas:

  1. Instead of moving video data to screen RAM, the Domination player CALLs the video frame code, which executes and then returns
  2. The read-and-fill-memory loop, as well as the interrupt handler pointer management code, deals with variably-sized video+audio packets; this is because the output of the encoder varies in size based on how many changes are present from frame to frame

Two changes were made to the muxed video+audio stream for Domination that not only enabled handling variably-sized packets, but also sped up disk reads. The first change was to align each packet of video+audio data to disk sector boundaries, which sped up disk reads due to the way DOS handles buffering: DOS will normally transfer disk requests into its own internal buffers (if you’ve ever wondered what the BUFFERS= line in CONFIG.SYS was for, now you know) and then copy to the caller’s buffer. However, if the caller requests reading a sector-aligned offset (and amount) into a normalized paragraph-aligned pointer, DOS is smart enough to instruct the BIOS to transfer the data directly to the caller’s buffer. This made disk reads return a little quicker, as DOS’s usual double-buffering step was avoided.

The second change to the player was to keep track of how large each video+audio packet was. Rather than put size headers before each chunk, or scan the entire file before starting to determine sizes, I chose to write an index to the end of the file stream. The index consists of one byte per video+audio packet, where each byte indicates the size of the packet in sectors; this is possible because each packet is guaranteed to be aligned to sectors. (This limits the size of each packet to (255*512) = 127.5KB, but we will never see a single frame that large in practice; in fact, we will never see a packet larger than 64KB because that is the 16-bit real-mode segment size limit.)

The most amount of time I spent enhancing the player for the Domination format was, to my surprise, the memory handling. The original player used a circular buffer (a FIFO queue) that fed disk data into the “head” while the interrupt handler grabbed data from the “tail”. Typical circular buffers are divided into fixed-size blocks, but I had just switched to variably-sized packets. I needed a FIFO that could:

  • Accept variably-sized allocations/deallocations
  • Manage a linear area of memory with wraparound without requiring that area to be a power-of-two length
  • Be interrupt-safe (ie. no locks/mutexes/semaphores required to put data in or pull data out)
  • Always return paragraph-aligned normalized pointers
  • Perform all of the above while dealing with 16-bit real-mode segment limitations

In the end, I wrote code that was not so much a typical circular buffer, but more of a heap manager where the caller “reserves” an amount of memory, receives a pointer to an area they can use, fills it with data, and then “commits” the area. Prior commits can be retrieved in FIFO order using another function. The design is interrupt-safe because reserves and commits don’t touch the data structures that are used by retrievals, and vice versa. I know it sounds stupid to be proud of a data structure, but I was pretty pleased with myself when I finished implementing it. (I’ve since learned there is a similar construct out there called a bip buffer, but a bip buffer wastes more memory and time than what I came up with.)

In Search Of Test Material

With two fully-functioning video modes supported by the encoder, I now had to choose some test material to show it off. For the color portion, I decided to use exactly the same footage that I’d used 10 years earlier with Corruption, so that people could directly compare them and see for themselves that the newer method was better overall. For the B&W portion, I had difficulty picking material; I was about to go with one of the old Apple silhouette-style ipod/itunes commercials until I saw a Game Sack episode where a homebrew Genesis cart was shown playing the Bad Apple animation. I was hooked — it was perfect test material. High-contrast shadow puppetry lent itself very well to my “animation compiler” because, most of the time, very little is actually changing per frame, and what is changing has very clean residuals.

Finding a clean source of the Bad Apple animation proved more difficult than I thought it would be. Every youtube version had resizing or transcoding artifacts, so after some research I found the original japanese video-sharing site it originated from and grabbed it from there, which resulted in an extremely clean 30fps source to work with.

Conclusion

8088 Domination may be my best work; I’m very proud of the result. I had to think creatively and unconventionally to solve problems. If people are considered artists based on the uniqueness and viewpoint of their output — paintings, novels, musical works — then I’d like to think programmers can be artists too, and judged by the same conventions.

I want to fix a few bugs in the source and tidy it up, and once I’ve done that I will release the source, executables, and documentation so that you can create your own videos using the system. Until then, enjoy a video of the competition I showed it at, complete with audience reaction:

Posted in Demoscene, Digital Video, Programming, Vintage Computing | 17 Comments »