Skip to content

cdmc: correct the IndyCam register map and power-on defaults#57

Open
hanshuebner wants to merge 1 commit into
techomancer:mainfrom
hanshuebner:pr/indycam-cdmc-register-map
Open

cdmc: correct the IndyCam register map and power-on defaults#57
hanshuebner wants to merge 1 commit into
techomancer:mainfrom
hanshuebner:pr/indycam-cdmc-register-map

Conversation

@hanshuebner

Copy link
Copy Markdown
Contributor

Live camera capture ([vino] source = "camera") came out uniformly green — luma and geometry correct, red and blue crushed to near zero. Reproduced on IRIX 6.5.22 with vidtomem -f /tmp/cap -v 0.

Two compounding bugs in the emulated CDMC:

The register map was wrong on every subaddress except VERSION (0x0E). The IndyCam map — same silicon the Linux indycam driver drives — is:

Sub Register Access Default
0x00 CONTROL (AGCENA, AWBCTL, EVNFLD) rw AGCENA
0x01 SHUTTER rw 0xFF
0x02 GAIN rw 0x80
0x03 BRIGHTNESS r 0x80
0x04 RED_BALANCE rw 0x18
0x05 BLUE_BALANCE rw 0xA4
0x06 RED_SATURATION rw 0x80
0x07 BLUE_SATURATION rw 0xC0
0x08 GAMMA rw 0x80
0x0E VERSION r 0x10
0x0F RESET w

Mapping VERSION to 0x00 also meant every CONTROL write was dropped as a write to a read-only register.

The register file powered up at all-zero while apply_uyvy_field treated 0x80 as each control's neutral point, so every unprogrammed control sat at its extreme. The balance and saturation terms pulled Cb and Cr from 128 down to 96, which through BT.601 is R−51, G+38, B−64 per pixel — exactly the observed cast. Note the hardware defaults are not uniformly 0x80, so "0x80 is neutral" is wrong even with a correct map.

Fix

apply_uyvy_field is anchored at the power-on values: with the defaults in place every term is unity and the field passes through byte-identical. Controls respond proportionally as the guest moves them away from default. AGCENA and AWBCTL suppress the gain and balance terms respectively, matching a host camera running its own auto-exposure and auto-white-balance. RESET and read-only enforcement are handled.

Verification

Isolated host capture from the guest first: a probe through the same nokhwa path showed macOS AVFoundation delivering correct 1920×1080 packed YUYV, clearing src/camera.rs. Replaying that real frame through Cdmc::apply_uyvy_field offline with candidate register states reproduced the reported green image exactly from the "gain set, everything else zero" state, and produced a clean frame with correct defaults.

Six new tests in src/cdmc.rs, including power_on_defaults_pass_the_field_through_untouched. Full suite passes (308).

Write-up in rules/irix/indycam-cdmc-register-map.md.

Not addressed

The live preview in the video tool is still grey. That is the separate continuous-capture gap noted in rules/irix/indycam-end-to-end-capture.mdread_channel_reg's field_counter >= 2 descriptor-table readback and dma_emit_dword's field_counter == 0 defer are one-shots tuned for a single interlaced frame, so nothing is delivered once a channel streams past the second field.

Also unconfirmed: which subaddresses the IRIX driver actually writes. The cast is cured either way since the defaults are now pass-through, but confirming the map end-to-end wants a run with log vino on.

🤖 Generated with Claude Code

Live camera capture came out uniformly green: luma and geometry correct,
red and blue crushed to near zero.

Every CDMC subaddress except VERSION (0x0E) was mapped to the wrong
control. The IndyCam register map is CONTROL 0x00, SHUTTER 0x01, GAIN
0x02, BRIGHTNESS 0x03 (read-only), RED_BALANCE 0x04, BLUE_BALANCE 0x05,
RED_SATURATION 0x06, BLUE_SATURATION 0x07, GAMMA 0x08, VERSION 0x0E
(read-only), RESET 0x0F. Mapping VERSION to 0x00 also made every CONTROL
write get dropped as a write to a read-only register.

The register file powered up at all-zero while apply_uyvy_field treated
0x80 as each control's neutral point, so every unprogrammed control sat
at its extreme. The balance and saturation terms pulled Cb and Cr from
128 down to 96, which through BT.601 is R-51, G+38, B-64 per pixel — the
green cast. The hardware defaults are not uniformly 0x80: red balance is
0x18 and blue saturation 0xC0.

apply_uyvy_field is now anchored at the power-on values, so a guest that
leaves the camera alone gets the host frame through byte-identical, and
controls respond proportionally as the guest moves them. AGCENA and
AWBCTL suppress the gain and balance terms, matching a host camera
running its own auto-exposure and auto-white-balance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hanshuebner

Copy link
Copy Markdown
Contributor Author
iris

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.

1 participant