Skip to content

fix: ensure XDG_DATA_DIRS contains system dirs so Vulkan drivers load#1742

Open
btlqql wants to merge 1 commit into
OpenAtom-Linyaps:masterfrom
btlqql:btlqql/issue-1457
Open

fix: ensure XDG_DATA_DIRS contains system dirs so Vulkan drivers load#1742
btlqql wants to merge 1 commit into
OpenAtom-Linyaps:masterfrom
btlqql:btlqql/issue-1457

Conversation

@btlqql

@btlqql btlqql commented Jul 12, 2026

Copy link
Copy Markdown

Summary

Fixes #1457 — Mesa3D Snapdragon Turnip (freedreno) Vulkan driver fails to load inside Linglong containers, while OpenGL works.

Root cause

The Vulkan ICD loader discovers driver manifests by scanning each entry of XDG_DATA_DIRS for a vulkan/icd.d subdirectory, and only falls back to /usr/local/share:/usr/share when XDG_DATA_DIRS is unset.

Inside a Linglong container the host XDG_DATA_DIRS — which on a Linyaps session points at Linyaps specific paths such as /var/lib/linglong/entries/share — can be forwarded into the container environment (e.g. via forwardEnv()). That overrides the loader's default search path, so the loader never scans /usr/share/vulkan/icd.d and enumerates no GPU.

This perfectly matches the reported symptoms:

  • OpenGL works — Mesa locates DRI drivers through the compiled-in library path, independent of XDG_DATA_DIRS.
  • Vulkan fails — the loader relies on XDG_DATA_DIRS-based discovery.
  • VK_ICD_FILENAMES=... works around it (as the maintainer confirmed), because that variable bypasses the directory search.

Fix

In ContainerCfgBuilder::buildEnv() (the central place where the container environment is assembled, used by both the ll-cli and UAB paths), ensure the conventional system data directories /usr/share and /usr/local/share are always part of XDG_DATA_DIRS:

  • preserve any existing/forwarded value (host specific paths are kept),
  • append the standard system directories when missing,
  • avoid duplicates and avoid rewriting the value when nothing changes.

This lets the Vulkan loader (and any other XDG-data consumer) keep discovering system-provided data such as the Mesa Turnip driver manifest at /usr/share/vulkan/icd.d, without requiring users to export VK_ICD_FILENAMES.

Files changed

  • libs/oci-cfg-generators/src/linglong/oci-cfg-generators/container_cfg_builder.cpp — normalize XDG_DATA_DIRS in buildEnv().
  • libs/linglong/tests/ll-tests/src/linglong/oci_cfg_generators/container_cfg_builder_test.cpp — new regression tests.
  • libs/linglong/tests/ll-tests/CMakeLists.txt — register the new test source.

Verification

Configured with cmake --preset debug and built linglong::linglong::ll-tests:

cmake --build build --target linglong__linglong__ll-tests

Ran the new tests plus the surrounding runtime/env suites:

./ll-tests --gtest_filter='ContainerCfgBuilderEnvTest.*:RunContextTest.*:RunContainerOptionsTest.*'

Result: 23/23 passed. The three new tests cover:

  1. XDG_DATA_DIRS unset → defaults added (/usr/share, /usr/local/share).
  2. host value forwarded → preserved, with system dirs appended.
  3. system dirs already present → no duplication, value untouched.

Full suite: 460 passed, 12 skipped (FUSE/display), 1 failure (Error.WarpStdErrorCode) which is pre-existing and environmental — it expects a non-root runner, while the CI sandbox runs as root so create_directory("/no_permission_to_create") succeeds.

clang-format --dry-run --Werror passes on both changed source files.

Risk / assumptions

  • The change only ever adds the standard system data directories to XDG_DATA_DIRS; it never removes existing entries, so application/desktop-entry data discovery is unaffected.
  • This addresses ICD discovery. It assumes the runtime/base layer actually ships the driver manifest (the base runtime's mesa-vulkan-drivers provides the freedreno ICD, as confirmed by the maintainer's test showing driver Mesa 24.3.0-1deepin1).

The Vulkan ICD loader discovers driver manifests by scanning each entry of
XDG_DATA_DIRS for a "vulkan/icd.d" subdirectory, falling back to
"/usr/local/share:/usr/share" only when XDG_DATA_DIRS is unset.
In a Linglong container the host XDG_DATA_DIRS (which on a Linyaps session
points at Linyaps specific paths such as /var/lib/linglong/entries/share) can
be forwarded into the container environment. That overrides the loader's
default search path, so the loader never looks into /usr/share/vulkan/icd.d
and fails to enumerate any GPU. This is why OpenGL keeps working (Mesa finds
DRI drivers through the compiled-in library path) while Vulkan does not, and
why exporting VK_ICD_FILENAMES works around it (issue OpenAtom-Linyaps#1457).
Always ensure the conventional system data directories remain part of
XDG_DATA_DIRS when assembling the container environment, preserving any
forwarded value and avoiding duplicates. This lets the Vulkan loader (and any
other XDG-data consumer) discover system provided data such as the Mesa
Turnip/freedreno driver manifest under /usr/share/vulkan/icd.d.
Resolves OpenAtom-Linyaps#1457.

Signed-off-by: btlqql <2977859784@qq.com>
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

Welcome @btlqql! It looks like this is your first PR to OpenAtom-Linyaps/linyaps 🎉

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: btlqql

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

Hi @btlqql. Thanks for your PR.

I'm waiting for a OpenAtom-Linyaps member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request ensures that conventional system data directories (/usr/local/share and /usr/share) remain reachable through XDG_DATA_DIRS in the container environment, which is necessary for the Vulkan ICD loader to discover system-provided driver manifests. It also adds corresponding unit tests to verify this behavior. The reviewer suggested optimizing the environment variable building logic to avoid unnecessary string copying and heap allocations when the system directories are already present.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +1526 to +1549
const std::vector<std::string> systemDataDirs{ "/usr/local/share", "/usr/share" };
auto xdgIt = environment.find("XDG_DATA_DIRS");
std::string currentValue = (xdgIt != environment.end()) ? xdgIt->second : std::string{};
auto entries =
common::strings::split(currentValue, ':', common::strings::splitOption::SkipEmpty);

std::vector<std::string> dirs;
dirs.reserve(entries.size() + systemDataDirs.size());
for (auto entry : entries) {
dirs.emplace_back(entry);
}

bool changed = (xdgIt == environment.end());
for (const auto &dir : systemDataDirs) {
if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end()) {
dirs.push_back(dir);
changed = true;
}
}

if (changed) {
environment["XDG_DATA_DIRS"] = common::strings::join(dirs, ':');
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

We can optimize this block to avoid unnecessary string copying and heap allocations:

  1. Use std::string_view for currentValue instead of copying xdgIt->second into a new std::string.
  2. Check if the system directories are already present in entries before allocating and copying elements into dirs. If they are already present, we can skip the entire update process entirely.
        const std::vector<std::string> systemDataDirs{ "/usr/local/share", "/usr/share" };
        auto xdgIt = environment.find("XDG_DATA_DIRS");
        std::string_view currentValue = (xdgIt != environment.end()) ? std::string_view{xdgIt->second} : std::string_view{};
        auto entries =
          common::strings::split(currentValue, ':', common::strings::splitOption::SkipEmpty);

        bool changed = (xdgIt == environment.end());
        if (!changed) {
            for (const auto &dir : systemDataDirs) {
                if (std::find(entries.begin(), entries.end(), dir) == entries.end()) {
                    changed = true;
                    break;
                }
            }
        }

        if (changed) {
            std::vector<std::string> dirs;
            dirs.reserve(entries.size() + systemDataDirs.size());
            for (auto entry : entries) {
                dirs.emplace_back(entry);
            }
            for (const auto &dir : systemDataDirs) {
                if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end()) {
                    dirs.push_back(dir);
                }
            }
            environment["XDG_DATA_DIRS"] = common::strings::join(dirs, ':');
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

【严重问题】Mesa3D的骁龙Turnip开源驱动加载失败

2 participants