Skip to content

Optimisations for the feeble computer - #10

Open
colinleroy wants to merge 4 commits into
richgel999:masterfrom
colinleroy:master
Open

Optimisations for the feeble computer#10
colinleroy wants to merge 4 commits into
richgel999:masterfrom
colinleroy:master

Conversation

@colinleroy

@colinleroy colinleroy commented Aug 7, 2025

Copy link
Copy Markdown

Hi,

and thanks for this very small JPEG decoder. I based my Apple II Quicktake 200 decoder on it thanks to its very small memory requirements.

I have hacked it A LOT (including ripping out every JPEG subformat that the Quicktake 200 does not produce, and hand-rewriting core functions into assembly), but I feel these few changes could benefit anybody.

I hope you'll like them :)

  • Huffman decoding:
    • we never use mMinCode's high byte, and we subtract mMinCode's low byte from mValPtr unconditionally, so do it when building the tables and drop it entirely.
    • use a dedicated mGetMore bool instead of a special-case mMaxCode 0xFFFF to consume one more byte
    • decodeNextMCU: branch a bit less selecting the Huff tables
  • General:
    • getExtendOffset: use arrays instead of functions and switches
    • skipVariableMarker: jump to the desired place much faster than left-shifting 8 times every byte we want to skip

Here is a before/after callgrind run (before on the left, after on the right):
image

Full callgrind logs (gcc -g -O0):
callgrinds.zip

- Huffman decoding:
  - we never use mMinCode's high byte, get rid of it
  - use a dedicated mGetMore bool instead of a
    special-case mMaxCode 0xFFFF to consume one more
    byte
  - decodeNextMCU: branch a bit less selecting the
    Huff tables
- General:
  - getExtendOffset: use arrays instead of functions
    and switches
  - skipVariableMarker: jump to the desired place much
    faster than left-shifting 8 times every byte we
    want to skip
@richgel999

Copy link
Copy Markdown
Owner

Thanks! I'm not working on this project at the moment, but I appreciate you posting this.

This is easier wrt the carry on 6502
Avoids extra array accesses to ZAG[k++] when skipping, and
extra loops
@colinleroy

Copy link
Copy Markdown
Author

Thanks! I'm not working on this project at the moment, but I appreciate you posting this.

No worry! I'll keep pushing some changes I use on my own decoder as long as they change 0 bits in the output images :)

Long shot question (as I think you understand the jpeg format better than me): in my decoder, I decode to grayscale because it's going to be displayed in 256x192 1bit anyway, so I skip the MCU coeff computation and the IDCT for that 3rd component. However, I still have to "pretend", consuming bits for nothing. Like you do for reduce mode, but with a if (mcublock < 2) condition instead, and I also throw out the DC component there.

I presume there are no markers in jpeg files that would tell one where in the file to skip to. That would be 2400*3 markers for a very edge use case. And if they existed, you'd have used them.

Anyway, thought I'd ask :)

@richgel999

Copy link
Copy Markdown
Owner

I presume there are no markers in jpeg files that would tell one where in the file to skip to.
Not really - the best you can get are restart markers, but they aren't guaranteed to even be in the input file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants