Skip to content

feat(#573)!: remove chroma-key everywhere — ABI v4 (runtime half) - #577

Merged
dfattal merged 5 commits into
mainfrom
chore/remove-chroma-key
Jun 14, 2026
Merged

feat(#573)!: remove chroma-key everywhere — ABI v4 (runtime half)#577
dfattal merged 5 commits into
mainfrom
chore/remove-chroma-key

Conversation

@dfattal

@dfattal dfattal commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Runtime half of #573 — the clean-slate removal of chroma-keying. True transparency (alpha swapchain + transparent DComp present + DP compose-under-bg / alpha-gate) fully replaces the chroma-key fallback. Coordinated ABI v3→v4 break, lockstep with displayxr-leia-plugin PR (feat/remove-chroma-key-573).

What's in here

  • P0 (gap-closing, no ABI change): render-API-agnostic transparent DComp presenter; D3D12 + GL IPC clients wired to it; GL in-process no-interop readback transparent present.
  • ABI v4 break: set_chroma_key removed from all 5 DP vtables; set_transparent_background added to D3D12 + GL DP vtables (d3d11/vk already had it); chroma_key_color/chromaKeyColor dropped from xrt_session_info + 5 compositor signatures + the oxr gfx chain; XR_EXT_win32_window_binding SPEC_VERSION 7→8; D3D11-service chroma pass + sim_display stubs deleted. XRT_PLUGIN_API_VERSION_CURRENT 3→4.

Validation

  • Builds clean (the per-vtable struct_size static_asserts catch any slot mistake).
  • displayxr-cli selftest passes only with a v4 plugin (v3 plugins → negotiate -17, ABI reject working).
  • Full v4 stack hardware-validated on the Leia box (D3D11/D3D12/GL/VK): 3D weave correct + transparent background composites the live desktop, across opaque and transparent modes.

Lockstep

Do not release the v4 runtime without the v4 Leia plugin — a v4 runtime rejects a v3 plugin. Paired with leia feat/remove-chroma-key-573; release together (runtime v1.18.0 + leia v1.8.0).

Closes #573.

🤖 Generated with Claude Code

dfattal and others added 5 commits June 14, 2026 02:59
Generalize the D3D11 client's ADR-029 transparent present (client owns the
DComp present on its own HWND because a process can't present cross-process
onto another's window) into a reusable, render-API-agnostic helper so the
D3D12/GL IPC clients can close their see-through gap without chroma-key.

- New comp_d3d_transparent_present.{h,cpp}: imports the service's shared
  NT-handle texture + service->client fence and presents on the app HWND
  (wait -> copy -> Present -> Commit). Reuses a passed ID3D11Device (D3D11
  client) or creates its own (D3D12/GL/VK) — the present is pure D3D11+DComp
  on shared handles, independent of the app's render API. C-callable shim so
  the .c GL client can use it.
- CMake: build it in the shared D3D block; link d3d11/dxgi/dcomp there.
- comp_d3d11_client.cpp: consume the helper (−131 lines), behavior-identical
  (passes its own app_device). This is the Windows verification anchor.

First step of removing chroma-keying everywhere (#573). VK over IPC already
done via #568; only D3D12/GL clients + GL no-interop in-process remain to
close before the ABI v4 deletion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The P0.1 helper was authored on macOS and never compiled. MSVC rejected it
on three counts (all in the new comp_d3d_transparent_present.{h,cpp}):

- header used uint64_t/uint32_t without <stdint.h> (xrt_handles.h doesn't
  pull it in) -> C2061 syntax error, which in turn made the .cpp definition
  look like an extern "C" overload (C2733).
- the own-device branch called xrt::compositor::client::createDevice(), but
  createDevice lives in xrt::auxiliary::d3d::d3d11 (d3d_d3d11_helpers.hpp)
  -> C3083/C2039/C3861.

Full runtime build is now clean (=== ALL DONE ===). D3D11-client behavior is
unchanged (it still passes its own app_device; the own-device branch is only
reached by the not-yet-wired D3D12/GL clients).

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

Close the D3D12 / GL forced-IPC see-through gap without chroma-key by reusing
the P0.1 render-API-agnostic presenter, mirroring the D3D11 client exactly.
Both pass NULL device so the helper stands up its own D3D11 device (the present
is pure D3D11 + DComp on the shared handles, independent of the app's render
API).

- comp_d3d12_client.cpp: + `transparent` field + destructor cleanup; after fence
  init in _create, call get_transparent_output(+_fence) RPCs and create the
  presenter (NULL device); present after both successful layer_commit paths
  (semaphore + plain).
- comp_gl_win32_client.{c,h}: same, but the parent GL client owns layer_commit,
  so save its fn ptr and wrap it (present after a successful base commit) — only
  when a presenter was created. Forward-declared the presenter in the C header.
- tests/CMakeLists.txt: the d3d12 + (Windows) opengl client unit tests now
  reference the IPC bridge symbols, so link `ipc_client` (as the d3d11 test
  already does).

VK client intentionally skipped — Android #568 already covers VK transparency
(service-presents-to-shared-Surface). Full runtime build clean (=== ALL DONE ===).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Close the last in-process see-through gap so chroma-key can be deleted: when
WGL_NV_DX_interop2 is unavailable (near-extinct hardware), the GL native
compositor previously fell back to an OPAQUE SwapBuffers. Add a glReadPixels →
D3D11 dynamic-texture upload → DComp blit readback path instead, so α=0 holes
still reveal the live desktop.

- Refactored the proven interop setup into gl_setup_dcomp_common (D3D11 device +
  PREMULTIPLIED composition swapchain + DComp bind + blit pipeline), shared by
  both the interop and readback setups; and gl_dcomp_blit_srv_present, shared by
  both present-frame paths. Interop path verified unchanged on RTX 3080 (still
  logs "DComp present path active … interop transit").
- Readback path weaves into a DEDICATED RGBA8 GL texture+FBO — NOT FBO 0. The
  window's default framebuffer has no usable alpha, so glReadPixels returned A=1
  and the see-through holes came out opaque black; a real RGBA target preserves
  the premultiplied alpha. glReadPixels row 0 = GL bottom = the interop transit's
  orientation, so the existing blit shader's V-flip is correct unchanged.
- DISPLAYXR_GL_FORCE_READBACK=1 forces the readback path on interop-capable GPUs
  for verification. Per-frame readback cost logged once.

Verified on the Leia box (in-process, DISPLAYXR_TRANSPARENT_BG=1): interop
regression + forced readback both present cleanly; readback see-through
Leia-eyeball-validated (live desktop through the holes, de-occlusions correct).

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

Phase 1 of removing the chroma-key transparency mechanism. ABI-breaking:
XRT_PLUGIN_API_VERSION_CURRENT 3→4; XR_EXT_win32_window_binding SPEC_VERSION
7→8. True transparency (alpha-capable swapchain + transparent present, landed in
P0) is now the sole path.

Display-processor interfaces (the ABI contract):
- Removed set_chroma_key from all five DP vtables (base/vk, d3d11, d3d12, gl,
  metal) — a mid-vtable slot, so every following slot shifts; renumbered every
  offset static_assert + the size assert in each header.
- Added set_transparent_background to the D3D12 and GL DP vtables (d3d11 + vk
  already had it; metal needs none — its compositor sets drawable clear-alpha
  itself). This carries the transparency *enable* that on d3d12/gl had been
  overloaded onto set_chroma_key.
- Deleted the per-API set_chroma_key wrapper helpers; added d3d12/gl
  set_transparent_background wrappers.

Runtime:
- Dropped chroma_key_color from xrt_session_info (xrt_compositor.h), all five
  compositor create signatures + the oxr session-gfx native plumbing + the
  XR_EXT read in oxr_session.c.
- The four in-process compositors (d3d11/d3d12/gl/vk) now call
  set_transparent_background(enabled, client_presents=false) instead of
  set_chroma_key — client_presents=false preserves the prior compose-under-bg
  behavior exactly (the old set_chroma_key carried no client_presents, so the DP
  defaulted to compose-under-bg). The GL DComp transparent present is
  independent and keeps working.
- Deleted the D3D11 service svc_chroma_key_* pass (shaders, ChromaKeySvcConstants,
  init/ensure/execute) + the ck_* resource fields.
- Removed chromaKeyColor from the extension struct.
- Bumped the oxr_plugin_stub ABI-drift static_assert to v4.

sim_display (in-repo v4 test double): deleted all five set_chroma_key stubs.

Verified on the Leia box: full runtime build clean (all ABI static_asserts pass);
`displayxr-cli selftest` PASSES with the freshly-built v4 sim_display (the v3
Leia + v3 sim plug-ins are correctly rejected, negotiate -17). The leia-plugin
chroma deletion + d3d12/gl set_transparent_background impls are the remaining
lockstep half (separate repo) before any tag/release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dfattal
dfattal force-pushed the chore/remove-chroma-key branch from 151e0f3 to 088b53f Compare June 14, 2026 10:00
@dfattal
dfattal merged commit f69f5b5 into main Jun 14, 2026
26 checks passed
@dfattal
dfattal deleted the chore/remove-chroma-key branch June 14, 2026 10:10
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.

Remove chroma-keying everywhere (clean slate) — ABI v4

1 participant