Skip to content

Host OpenGL for IRIX programs: hostcall + hostgl - #152

Merged
techomancer merged 2 commits into
techomancer:mainfrom
atomchild411:hostgl
Sep 30, 2026
Merged

techomancer merged 2 commits into
techomancer:mainfrom
atomchild411:hostgl

Conversation

@atomchild411

Copy link
Copy Markdown
Contributor

Host-accelerated OpenGL for IRIX programs, as two commits:

  1. hostcall: host services through a private system call. An IRIX
    program makes an ordinary syscall numbered 3000-3009, which IRIX does
    not use; IRIS answers it in exec_syscall before any exception and the
    program carries on at the next instruction. Only user-mode calls outside
    a delay slot, and only numbers a service is registered for; everything
    else goes to IRIX untouched. On a real machine, or IRIS built without
    this, the call fails with EINVAL, which is how a library tells. A
    "need page" answer covers memory that is not in the TLB yet: the caller
    touches the page, IRIX faults it in as usual, and the call is made again
    with its progress kept. Includes a self-test service (3009) and a unit
    test that runs a real syscall through the trap. --features hostcall,
    off by default.
  2. hostgl: OpenGL on the host GPU, over host call 3000. The guest runs
    a replacement libGL that encodes GL calls into a command buffer; the
    buffer comes over in one host call whenever the host is needed (a
    result, memory read or written in place, a swap) and iris-hostgl
    replays it on the host's OpenGL. On IMPACT, frames are composited
    straight into the framebuffer under their window. Both sides of the wire
    format are generated from one description built from the Khronos OpenGL
    registry (gl.xml, pinned, Apache-2.0) plus annotations for what IRIX
    6.5 declares differently; regenerating reproduces the committed decoder
    and the published guest encoders byte for byte. --features hostgl
    (implies hostcall). The only backend is Apple's CGL: on other hosts
    the crate builds and registers nothing, and the guest libGL says host GL
    is unavailable.

The IRIX side is https://github.com/atomchild411/iris-guest-tools
(BSD-3-Clause): libGL.so/libgl.so replacements, the host call trap,
tests (glcheck, gltest, irisgltest, glbench, hostcall_test) and
install scripts.

Testing

  • cargo test: iris-hostcall (3), iris-hostgl (26, real CGL contexts on
    macOS), lib with hostgl,ip28,jitv2 (1180); cargo check clean with and
    without the features. The Linux build is checked by reading the cfgs
    only (no Linux target here): everything platform-specific is behind
    target_os = "macos", so CI will be the first real Linux build.
  • IP28 + IMPACT, IRIX 6.5.22m, --features ip28,chd,hostgl,jitv2,tcache
    on an M4 Pro: the guest tools built from that repository, run as a
    logged-in user on :0. hostcall_test passes (ping, sum, fill with
    hundreds of need-page retries, copy-on-write child, kernel address
    refused); glcheck, irisgltest and glbench pass with the same frame
    checksums as our earlier tree; gr_osview (OpenGL on 6.5.22) draws on
    the IMPACT desktop.
  • One known intermittent failure, not new: gltest's "the window kept its
    pixels" (draw in a window, switch to a pbuffer and back, read the window)
    failed 4 times in 27 runs today, with the guest library from this
    repository and with our earlier one alike.

🤖 Generated with Claude Code

atomchild411 and others added 2 commits September 30, 2026 01:16
An IRIX program asks IRIS for something the emulated machine does not
have by making an ordinary `syscall` with a number IRIX does not use:
3000-3009 (IRIX's highest in 6.5 is 1234). IRIS answers it in
`exec_syscall`, before any exception, and the program resumes at the
next instruction; the kernel never runs. On a real machine, or an IRIS
built without this, an indirect call to one of these numbers fails with
EINVAL (measured on real IRIX), which is how a library finds out it is
not running here.

The trap answers only user-mode `syscall`s outside a delay slot, and
only for a number a service is registered for; everything else goes to
IRIX untouched. Results come back the IRIX way (v0, v1, a3), plus one
outcome of our own, "need page": IRIS sees the TLB, not IRIX's page
tables, so a call that needs a page of the program's memory that is not
in the TLB, not paged in, or not yet writable answers ENEEDPAGE with the
page. The caller touches it, which makes IRIX fault it in as for any
access, and calls again; progress is kept across retries, so a buffer
larger than the TLB still gets through. Program memory is read and
written through DEBUG translation under the current ASID, user addresses
only.

iris-hostcall/ holds the numbers, the register protocol, the service
registry and a self-test service (3009: ping, byte sum, fill), which is
registered whenever the feature is built in. Behind `--features
hostcall`, off by default. The first service to use it is host OpenGL,
in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IRIX OpenGL programs draw on the host's GPU. They are given a
replacement libGL (the iris-guest-tools project,
github.com/atomchild411/iris-guest-tools, installed in place of SGI's
under the same SONAME) whose entry points encode themselves into a
command buffer; the buffer reaches the host in one host call whenever a
call needs the host before it returns (a result, memory read or written
in place, a swap) or the buffer is full. iris-hostgl replays it on the
host's OpenGL: a legacy-profile context per GLX context, a framebuffer
object per drawable. SGI extensions the host lacks are done in the
fragment stage with shaders.

A swap flips the frame on the GPU and presents it: on IMPACT the board
composites it into its framebuffer under the window (`ImpactScreen`,
`Mgras::composite`); otherwise the pixels go back to the program, which
puts them up with XShmPutImage/XPutImage. Program memory is read and
written through hostcall's need-page protocol, so buffers larger than
the TLB work and nothing in IRIX changes.

Both halves of the wire protocol -- this crate's decoder (src/calls.rs)
and the guest library's encoders -- are generated by tools/glshim.py
from one description, tools/glapi.json, which tools/glapi_from_registry.py
builds from the Khronos OpenGL registry (tools/khronos/gl.xml, pinned,
Apache-2.0, see its README) plus our annotations of what IRIX 6.5
declares differently. Regenerating from this tree reproduces calls.rs
and the published guest encoders byte for byte. A handshake checks the
protocol number, so a library and an emulator that disagree refuse each
other.

The only backend is Apple's CGL: on macOS `--features hostgl` registers
the service; elsewhere the crate builds and registers nothing, and the
guest library reports that host GL is not available.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@danifunker

Copy link
Copy Markdown
Collaborator

Can you add a feature-flag opt-in on this instead of just determining by platform? We might be distributing on additional platforms which may have this to cause issues. Also other architectures may not support this hostgl application as easily.

@techomancer

Copy link
Copy Markdown
Owner

i will add feature flag in the next commit

@techomancer
techomancer merged commit 1a93808 into techomancer:main Sep 30, 2026
8 checks passed
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.

3 participants