在软件体积不断膨胀的今天,Demoscene 社区却在进行一场逆向工程 —— 用越来越少的字节创造越来越震撼的视听效果。从 64KB 到 4KB,再到 256 字节、64 字节,直至 16 字节的极限前沿,Size-Coding 不仅是一种编程技巧,更是一门关于取舍、压缩与算法美学的工程艺术。
极限的起点:16 字节能做什么
在 MS-DOS 的.COM 格式中,一个程序可以从第一个字节就开始执行,没有头部开销,没有强制初始化。这种 "零开销" 特性使 DOS 成为 Size-Coding 的理想平台。然而,即便是这样一个极简环境,16 字节的上限仍然令人窒息。
以经典的 VGA 模式 13h(320×200 分辨率,256 色)为例,仅初始化图形模式和设置显存段寄存器就需要 8 个字节:
MOV AL, 13H ; 设置图形模式
INT 10H ; 调用BIOS
PUSH 0A000H ; 显存段地址
POP ES ; 存入ES寄存器
剩下的 8 字节中,无限循环(JMP)和像素写入(STOSB)又占去 3 字节,仅剩 5 字节用于实现实际效果。在如此严苛的限制下,"TV Noise" 这类简单效果已是极限。
然而,Viznut 的实验表明,16 字节并非只能产生无意义的噪点。通过巧妙地利用系统定时器($A1/$A2)的递增特性,结合 XOR、OR 等位运算,可以在音频和视频寄存器上创造出具有节奏感和宏观结构的 "类演示" 效果。这种 "混沌中的秩序" 正是 Size-Coding 的魅力所在。
256 字节的宏大舞台:Memories 案例分析
当字节预算扩展到 256 字节时,可能性空间呈指数级增长。HellMood 在 2020 年 Revision 大赛上的获奖作品 "Memories" 展示了这一预算下的工程极限 —— 一个包含 8 个视觉效果、MIDI 音乐、平滑过渡的 "微型演示"。
核心优化技术
Rrrola Trick:坐标变换的魔法
在 VGA 模式 13h 中,屏幕像素以行优先方式存储。传统方法用除法和取模计算 X、Y 坐标,但在 Size-Coding 中这是奢侈的。Rrrola Trick 使用魔数 0xCCCD 与屏幕指针 DI 相乘,通过高位和低位寄存器直接获得 X、Y 坐标:
MOV AX, 0CCCDH
MUL DI ; DX = Y, AX = X * 0.8
ADD AL, AH
XOR AH, AH ; AL = 伪随机值
这个技巧不仅避免了昂贵的 DIV 指令,还顺便产生了可用于效果的伪随机值。
寄存器复用:每一比特都珍贵
在 x86 实模式下,AX、BX、CX、DX 等寄存器是稀缺资源。Memories 框架中,DX 寄存器同时承载 X(DL)和 Y(DH)坐标;BP 寄存器既是时间计数器,又被 MIDI 音乐生成复用。这种 "寄存器重叠使用" 策略要求对指令副作用有精确把控。
代码与数据的双重压缩
Memories 中的 MIDI 音乐生成展示了极致的代码复用:
SOUNDS: DB 0C3H, 11, 93H
这里的 0C3H 既是 MIDI 的 "选择乐器" 指令,又恰好是 x86 的 RET 指令。通过精心安排代码布局,单个字节承担双重语义,节省了宝贵的字节预算。
效果实现的工程参数
Memories 中的 8 个效果展示了不同视觉算法的参数化实现:
Sierpinski Rotozoomer
传统旋转缩放需要三角函数计算,但 Memories 使用了一个数学技巧:利用 tan (atan (T)) = T 的特性,将缩放因子与旋转角度绑定,完全避免了三角函数调用。
Raycast Bent Tunnel
通过将距离值(CL)与投影坐标相乘,实现了伪 3D 隧道效果。关键参数包括:
- 起始深度:-9(向后移动)
- 弯曲偏移:+CL(向右弯曲)
- 纹理模式:MOD 6 产生不规则图案
Ocean Night-to-Day
利用 FPU 的整数加载 / 浮点存储特性,通过将 XY 坐标解释为浮点数进行反向除法,生成波浪效果。天空到日出的颜色渐变则是 "框架副作用"—— 通过代码布局使 AL 寄存器恰好指向合适的调色板位置。
可落地的优化清单
对于希望实践 Size-Coding 的开发者,以下参数和技巧可直接应用:
初始化参数
- 模式设置:AL = 0x13(320×200×256)
- 显存段:ES = 0xA000
- 定时器端口:40H(通道 0)
- MIDI 端口:330H
核心常数
- Rrrola 魔数:0xCCCD(坐标变换)
- 投影常数:0x1329(倾斜平面效果)
- 迭代魔数:819(视差棋盘效果)
渲染优化
- 三重隔行扫描:通过 INC DI 两次实现,平滑动画
- 目标帧率:35 FPS(tempo = 1193182/256/35)
- 伪随机生成:屏幕指针 DI 的变换残差
寄存器分配策略
- DI:屏幕指针(硬件自动递增)
- BP:时间 / 帧计数器
- DX:X/Y 坐标(DL/DH 分割)
- AL:像素颜色值(STOSB 要求)
从极限到工程实践
Size-Coding 的技术不仅适用于演示程序。在嵌入式系统、引导加载程序、网络协议栈等场景中,类似的优化思维同样适用:
- 算法替代存储:用运行时计算替代查找表,在 RAM 受限设备中尤为重要
- 副作用编程:利用指令的隐式行为(如标志位、寄存器高位)传递信息
- 布局优化:通过代码重排使数据天然对齐,减少初始化开销
- 硬件直通:绕过抽象层直接操作寄存器,降低延迟和代码体积
Size-Coding 的哲学提醒我们:软件的本质复杂度往往远低于其实现复杂度。在 111MB 甚至更大的限制下,我们或许已经忘记了如何精打细算;但 16 字节的前沿探索,让我们重新认识到每一比特的价值。
参考来源
- SizeCoding.org Wiki - "Memories" 详细技术解析
- Viznut - "The 16-byte frontier: extreme results from extremely small programs"
- Pouet.net - Demoscene 作品档案库
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。