TC$mC$ on **huikea onnistuminen**, vaikka ruudulla nC$kyykin "vC$rioksennusta"!
Jos katsot tarkkaan QEMU-ruutukaappaustasi ja vertaat sitC$ alkuperC$iseen
`KUVA.JPG` -tiedostoon, huomaat ettC$ **kuviot ja muodot tC$smC$C$vC$t
tC$ydellisesti!** Sateenkaaren diagonaaliset linjat ovat juuri oikeilla
paikoilla.
TC$mC$ tarkoittaa, ettC$ koko massiivinen arkkitehtuurisi toimi: 21 Kt
tiedosto luettiin suoraan ATA-laitteistolta, Bump Allocator antoi sille 2MB
muistia, NanoJPEG purki Huffman-taulut ja IDCT-matematiikan tC$ysin oikein
C-tasolla.
### Miksi vC$rit ovat sekaisin? (Paljaan metallin realiteetit)
Koodissamme on rivi: `uint8_t vga_color = 16 + (cr * 36) + (cg * 6) + cb;`
TC$mC$ kaava olettaa, ettC$ kC$ytC6ssC$ on modernien Linux-terminaalien (Xterm
256) standardipaletti, jossa indeksit 16231 muodostavat tC$ydellisen 6x6x6
RGB-vC$rikuution.
Mutta me olemme paljaalla metallilla! Kun Hauki OS kytkee VGA-kortin Mode 13h
-tilaan, laitteisto lataa BIOSistaan ikivanhan **vuoden 1987 DOS-oletuspaletin*
*. Tuossa paletissa indeksi 16 on musta, indeksit 1731 ovat harmaasC$vyjC$, ja
loput ovat tC$ysin satunnaisia vC$rejC$ ohjelmamme nC$kC6kulmasta. Siksi
oikeiden sC$vyjen tilalle tulee suuria mustia aukkoja ja kirkkaita
perusvC$rejC$.
### Ratkaisu: Ohjelmoidaan VGA DAC (Digital-to-Analog Converter)
Korjataksemme tC$mC$n, meidC$n tC$ytyy kertoa nC$ytC6nohjaimelle suoraan,
miltC$ haluamme indeksien 16231 nC$yttC$vC$n. Laitteistotasolla tC$mC$
tehdC$C$n puhumalla IO-porteille `0x3C8` (Paletin indeksi) ja `0x3C9`
(RGB-data).
VGA DAC on historiallisista syistC$ **6-bittinen**, eli vC$riarvot annetaan
asteikolla `0-63` (ei 0-255).
Avaa `kernel_js.c` ja korvaa nykyinen `render_jpeg_to_vga` -funktio tC$llC$
pC$ivitetyllC$ versiolla:
```c
/ =============================================================================
=
/ RGB -> VGA 13h (256-color) MUUNNIN & DAC PALETIN OHJELMOINTI
/ =============================================================================
=
extern uint8_t vga_backbuffer[64000];
void render_jpeg_to_vga(uint8_t* rgb, int w, int h) {
// 1. Ohjelmoidaan VGA DAC sisC$ltC$mC$C$n 6x6x6 RGB-vC$rikuutio
// Portti 0x3C8: Paletin aloitusindeksi
// Portti 0x3C9: R, G, B arvot perC$kkC$in (0-63 asteikolla)
outb(0x3C8, 16);
for (int r = 0; r < 6; r++) {
for (int g = 0; g < 6; g++) {
for (int b = 0; b < 6; b++) {
// Skaalataan 0-5 arvo 0-63 VGA DAC-alueelle (5 * 51 / 4 = 63)
outb(0x3C9, (r * 51) / 4);
outb(0x3C9, (g * 51) / 4);
outb(0x3C9, (b * 51) / 4);
}
}
}
// 2. PiirretC$C$n pikselit nC$yttC6muistiin uudella paletilla
for (int y = 0; y < h && y < 200; y++) {
for (int x = 0; x < w && x < 320; x++) {
int idx = (y * w + x) * 3;
uint8_t r = rgb[idx];
uint8_t g = rgb[idx+1];
uint8_t b = rgb[idx+2];
// Skaalataan 255 -> 5 (eli 0-5)
uint8_t cr = (r * 5) / 255;
uint8_t cg = (g * 5) / 255;
uint8_t cb = (b * 5) / 255;
uint8_t vga_color = 16 + (cr * 36) + (cg * 6) + cb;
vga_backbuffer[y * 320 + x] = vga_color;
}
}
}
```
Kun kC$C$nnC$t ytimen tC$llC$ (`./make_kernel.sh`) ja suoritat `/jpeg`, C-ydin
syC6ttC$C$ laitteistoporttiin oman kustomoidun palettimme juuri ennen kuvan
purkamista. Nyt pikselien muodot pysyvC$t samoina, mutta vC$rit asettuvat
kohdilleen ja nC$et upean, pehmeC$n plasmakuvion! TC$mC$n lC$hemmC$s rautaa ei
kuvankC$sittelyssC$ enC$C$ pC$C$se.