Skip to content

feat(dx12): DirectComposition path for per-pixel alpha (#298) - #299

Merged
kolkov merged 3 commits into
mainfrom
feat/dx12-directcomposition
Aug 2, 2026
Merged

feat(dx12): DirectComposition path for per-pixel alpha (#298)#299
kolkov merged 3 commits into
mainfrom
feat/dx12-directcomposition

Conversation

@kolkov

@kolkov kolkov commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add DirectComposition (DComp) path for DX12 swap chain creation, enabling per-pixel alpha transparency (CompositeAlphaModePremultiplied)
  • CreateSwapChainForHwnd only supports DXGI_ALPHA_MODE_IGNORE — per-pixel alpha requires CreateSwapChainForComposition via DirectComposition visual tree
  • Lazy-load dcomp.dll via sync.Once (Windows 8+, always present on our min Win10 1809)
  • Auto-select: AlphaMode == Premultiplied → DComp path, Opaque → HWND path (unchanged)
  • Fix adapter to report Premultiplied only when dcompAvailable()
  • GOGPU_DX12_FORCE_HWND=1 env var for RenderDoc compatibility

Changes (5 files, +507/-27 LOC)

File Change
hal/dx12/dcomp.go New. DComp COM bindings: lazy dll loading, IDCompositionDevice/Target/Visual vtbl, dcompState lifecycle (init/bindSwapChain/release)
hal/dx12/dxgi/factory.go CreateSwapChainForComposition wrapper on IDXGIFactory6
hal/dx12/surface.go createSwapchain branching: DComp vs HWND based on AlphaMode. MakeWindowAssociation guarded for DComp path (Rust wgpu parity)
hal/dx12/instance.go dcomp *dcompState field on Surface. Teardown in Unconfigure. Alpha mode change detection in Configure (forces full recreate instead of ResizeBuffers)
hal/dx12/adapter.go Both Adapter and AdapterLegacy: Premultiplied conditional on dcompAvailable()

Architecture (ADR-057)

AlphaMode == Premultiplied:
  DCompositionCreateDevice2(NULL) → device
    → CreateTargetForHwnd(hwnd, false) → target
    → CreateVisual() → visual → target.SetRoot(visual)
  factory.CreateSwapChainForComposition(queue, desc) → swapchain
  visual.SetContent(swapchain) → device.Commit()

AlphaMode == Opaque:
  factory.CreateSwapChainForHwnd(queue, hwnd, desc) → swapchain  (unchanged)

Enterprise review findings (all addressed)

  • vtbl index 15 for SetContent: verified against Windows SDK + Rust wgpu
  • IID GUID {C37EA93A-E7AA-450D-B16F-9746CB0407F3}: verified
  • All error paths clean up DComp + swapchain resources: verified (5 paths)
  • Teardown order: swapchain → visual → target → device: verified
  • Alpha mode change during resize: detected, forces full recreate
  • MakeWindowAssociation: skipped on DComp path (Rust wgpu parity)
  • ResizeBuffers preserves COM identity, DComp visual retains reference: verified

Requires (separate repo)

gogpu#361: WS_EX_NOREDIRECTIONBITMAP window style + AlphaMode passthrough in renderer. Without this, DComp swap chain works but transparency is not visible (DWM redirection surface provides opaque background).

Test plan

  • go build ./... (Windows, Linux, macOS)
  • golangci-lint run --timeout=5m — 0 issues
  • gofmt — clean
  • Cross-platform build: GOOS=linux, GOOS=darwin
  • Visual: Opaque window renders correctly (regression)
  • Visual: Premultiplied + WS_EX_NOREDIRECTIONBITMAP → transparent (requires gogpu#361)
  • Visual: GOGPU_DX12_FORCE_HWND=1 falls back to HWND path

kolkov added 3 commits August 2, 2026 16:49
…ition wrapper (#298)

FEAT-DCOMP-001: CreateSwapChainForComposition method on IDXGIFactory6
FEAT-DCOMP-002: dcomp.go — lazy dcomp.dll loading, COM vtbl structs
(IDCompositionDevice/Target/Visual), dcompState lifecycle

Foundation for per-pixel alpha transparency via DirectComposition.
ADR-057, Rust wgpu dcomp.rs parity.
FEAT-DCOMP-003: createSwapchain branches on AlphaMode — Premultiplied
uses CreateSwapChainForComposition + DComp visual, Opaque uses HWND.
DComp teardown in Unconfigure (reverse order after swapchain release).
GOGPU_DX12_FORCE_HWND=1 env var for RenderDoc compatibility.

FEAT-DCOMP-004: adapter reports Premultiplied only when dcompAvailable().
Both Adapter and AdapterLegacy fixed.
…298)

- Configure: detect Opaque↔Premultiplied change, force full recreate
  instead of ResizeBuffers (which cannot change alpha mode)
- MakeWindowAssociation: skip on DComp path (Rust wgpu parity)
- Found by enterprise code review
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kolkov
kolkov merged commit 46d6748 into main Aug 2, 2026
15 checks passed
@kolkov kolkov mentioned this pull request Aug 2, 2026
@kolkov
kolkov deleted the feat/dx12-directcomposition branch August 2, 2026 15:05
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