#6010

fix(linux/cuda): map GL textures into CUDA once instead of per frame

OpenNiewiarowskiwants to merge intofrom

Description

With NVENC on Linux, streaming through the GL→CUDA path (gl_cuda_vram_t, used for DMA-BUF frames from KMS, wlroots and PipeWire capture) costs other GPU work throughput, and the loss grows with the stream framerate.

convert() called cuGraphicsMapResources and cuGraphicsUnmapResources on every frame. Each pair is a synchronizing GL↔CUDA handshake, so the GPU sits idle once per frame.

The textures are now mapped once in set_frame() and stay mapped until the device is destroyed. The destructor unmaps them before the resources are unregistered. Because mapping no longer orders GL and CUDA access, convert() waits on a GL fence before the CUDA copies, and records a CUDA event that it waits on before GL writes the textures for the next frame. NvFBC and software encoding use other paths and are unchanged.

RTX 5070 Ti, driver 615.78.08, 3024x1898 at 120 FPS, HEVC, KWin capture, with a game in a static scene on the same GPU (nvidia-smi, 45 s per build):

BuildGPU utilizationPower
master87%201 W
This PR100%223 W

Screenshot

Issues Fixed or Closed

  • Fixes #4567

Roadmap Issues

Testing

Arch Linux, GCC 15, CUDA 13.4, -DBUILD_TESTS=ON -DBUILD_WERROR=ON -DSUNSHINE_ENABLE_CUDA=ON: builds without warnings. clang-format 23.1.0 reports no changes.

No regression test: gl_cuda_vram_t is internal to cuda.cpp and needs an NVIDIA GPU and an EGL context, and the bug is lost throughput rather than wrong output.

  • Streamed with this build on the machine above and benchmarked it against master (table above). No errors in the log, and the fence never timed out.

Not tested: KMS and wlroots capture, 10-bit/HDR, YUV 4:4:4.

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Tests have been added or updated for new or modified functionality, including regression tests for bug fixes

AI Usage

See our AI usage policy.

  • AI tools were used while preparing this PR

An AI agent investigated the stall, wrote the fix, ran the builds and benchmarks, and drafted this description. I reviewed the diff and the results.