Skip to content

Commit 08b1e83

Browse files
committed
✨ Detect layers disabled by the loader
fixes #33
1 parent 64e6e5d commit 08b1e83

File tree

9 files changed

+111
-15
lines changed

9 files changed

+111
-15
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ add_library(
5151
linters/DuplicatesLinter.cpp
5252
linters/OrderingLinter.cpp
5353
linters/DisabledByEnvironmentLinter.cpp
54-
54+
linters/SkippedByLoaderLinter.cpp
5555
)
5656
target_link_libraries(linters PUBLIC lib)
5757
target_include_directories(

src/LoaderData.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ LoaderData QueryLoaderDataInCurrentProcess() {
4141
= xrEnumerateApiLayerProperties(layerCount, &layerCount, layers.data());
4242

4343
for (auto&& layer: layers) {
44-
ret.mEnabledLayerNames.emplace_back(layer.layerName);
44+
ret.mEnabledLayerNames.emplace(layer.layerName);
4545
}
4646

4747
return ret;

src/LoaderData.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
#include <openxr/openxr.h>
66

77
#include <string>
8-
#include <vector>
8+
#include <unordered_set>
99

1010
namespace FredEmmott::OpenXRLayers {
1111

1212
struct LoaderData {
1313
XrResult mQueryExtensionsResult {XR_RESULT_MAX_ENUM};
1414
XrResult mQueryLayersResult {XR_RESULT_MAX_ENUM};
1515

16-
std::vector<std::string> mEnabledLayerNames;
16+
std::unordered_set<std::string> mEnabledLayerNames;
1717

1818
// It's possible for runtimes to modify the environment variables,
1919
// which can disable API layers
20-
std::vector<std::string> mEnvironmentVariablesBeforeLoader;
21-
std::vector<std::string> mEnvironmentVariablesAfterLoader;
20+
std::unordered_set<std::string> mEnvironmentVariablesBeforeLoader;
21+
std::unordered_set<std::string> mEnvironmentVariablesAfterLoader;
2222
};
2323

2424
void from_json(const nlohmann::json&, LoaderData&);

src/Platform.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <filesystem>
66
#include <functional>
77
#include <optional>
8+
#include <unordered_set>
89

910
#include <imgui.h>
1011

@@ -29,7 +30,7 @@ class Platform {
2930
virtual std::expected<LoaderData, std::string> GetLoaderData() = 0;
3031
virtual std::vector<std::filesystem::path> GetNewAPILayerJSONPaths() = 0;
3132
virtual std::optional<std::filesystem::path> GetExportFilePath() = 0;
32-
virtual std::vector<std::string> GetEnvironmentVariableNames() = 0;
33+
virtual std::unordered_set<std::string> GetEnvironmentVariableNames() = 0;
3334
virtual float GetDPIScaling() = 0;
3435

3536
// Use OS/environment equivalent to Explorer

src/linters/DisabledByEnvironmentLinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class DisabledByEnvironmentLinter final : public Linter {
1313
std::vector<std::shared_ptr<LintError>> errors;
1414

1515
for (const auto& [layer, details]: layers) {
16-
if (!std::filesystem::exists(layer.mJSONPath)) {
16+
if (details.mState != APILayerDetails::State::Loaded) {
1717
continue;
1818
}
1919

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2023 Fred Emmott <[email protected]>
2+
// SPDX-License-Identifier: ISC
3+
4+
#include <fmt/format.h>
5+
6+
#include "Linter.hpp"
7+
#include "LoaderData.hpp"
8+
#include "Platform.hpp"
9+
10+
namespace FredEmmott::OpenXRLayers {
11+
class SkippedByLoaderLinter final : public Linter {
12+
virtual std::vector<std::shared_ptr<LintError>> Lint(
13+
const APILayerStore*,
14+
const std::vector<std::tuple<APILayer, APILayerDetails>>& layers) {
15+
const auto loaderData = Platform::Get().GetLoaderData();
16+
if (!loaderData) {
17+
return {};
18+
}
19+
20+
std::vector<std::shared_ptr<LintError>> errors;
21+
22+
for (const auto& [layer, details]: layers) {
23+
if (details.mState != APILayerDetails::State::Loaded) {
24+
continue;
25+
}
26+
if (!layer.IsEnabled()) {
27+
continue;
28+
}
29+
30+
if (loaderData->mEnabledLayerNames.contains(details.mName)) {
31+
continue;
32+
}
33+
34+
const auto& enableEnv = details.mEnableEnvironment;
35+
if ((!enableEnv.empty()) && !std::getenv(enableEnv.c_str())) {
36+
continue;
37+
}
38+
39+
const auto& disableEnv = details.mDisableEnvironment;
40+
if (!disableEnv.empty()) {
41+
if (std::getenv(disableEnv.c_str())) {
42+
continue;
43+
}
44+
if (
45+
loaderData->mEnvironmentVariablesAfterLoader.contains(disableEnv)
46+
&& !loaderData->mEnvironmentVariablesBeforeLoader.contains(
47+
disableEnv)) {
48+
errors.push_back(
49+
std::make_shared<LintError>(
50+
fmt::format(
51+
"This layer is blocked by your current OpenXR runtime",
52+
details.mName),
53+
PathSet {layer.mJSONPath}));
54+
continue;
55+
}
56+
}
57+
58+
errors.push_back(
59+
std::make_shared<LintError>(
60+
fmt::format(
61+
"Layer appears enabled, but is not loaded by OpenXR; it may be "
62+
"blocked by your runtime vendor",
63+
details.mName),
64+
PathSet {layer.mJSONPath}));
65+
}
66+
return errors;
67+
}
68+
};
69+
70+
// Unused, but we care about the constructor
71+
[[maybe_unused]] static SkippedByLoaderLinter gInstance;
72+
73+
}// namespace FredEmmott::OpenXRLayers

src/windows/SaveReport_wWinMain.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
#include <Windows.h>
55

6+
#include <shellapi.h>
7+
68
#include "CheckForUpdates.hpp"
9+
#include "LoaderData.hpp"
710
#include "Platform.hpp"
811
#include "SaveReport.hpp"
912

@@ -21,6 +24,16 @@ int WINAPI wWinMain(
2124
[[maybe_unused]] auto fireAndForget = CheckForUpdates();
2225
}
2326

27+
int argc {};
28+
const wil::unique_any<LPWSTR*, decltype(&LocalFree), &LocalFree> argv {
29+
CommandLineToArgvW(GetCommandLineW(), &argc)};
30+
31+
constexpr std::wstring_view LoaderQuery {L"loader-query"};
32+
if (argc == 2 && argv.get()[1] == LoaderQuery) {
33+
FredEmmott::OpenXRLayers::LoaderMain();
34+
return 0;
35+
}
36+
2437
// Make the file picker high-DPI if supported
2538
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
2639

src/windows/WindowsPlatform.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
#include <Unknwn.h>
77
#include <Windows.h>
88

9-
#include <winrt/base.h>
10-
119
#include <wil/com.h>
1210
#include <wil/resource.h>
1311

@@ -215,8 +213,9 @@ void WindowsPlatform::ShowFolderContainingFile(
215213
SHOpenFolderAndSelectItems(pidl.get(), 0, nullptr, 0);
216214
}
217215

218-
std::vector<std::string> WindowsPlatform::GetEnvironmentVariableNames() {
219-
std::vector<std::string> ret;
216+
std::unordered_set<std::string> WindowsPlatform::GetEnvironmentVariableNames() {
217+
std::unordered_set<std::string> ret;
218+
220219
wil::unique_environstrings_ptr env {GetEnvironmentStringsW()};
221220
std::string buf;
222221

@@ -230,9 +229,8 @@ std::vector<std::string> WindowsPlatform::GetEnvironmentVariableNames() {
230229
buf.resize_and_overwrite(byteCount + 1, [=](auto p, const auto size) {
231230
return WideCharToUTF8(it, nameEnd, p, size);
232231
});
233-
ret.emplace_back(buf.data(), static_cast<std::size_t>(byteCount));
232+
ret.emplace(buf.data(), static_cast<std::size_t>(byteCount));
234233
}
235-
std::ranges::sort(ret);
236234
return ret;
237235
}
238236

@@ -399,6 +397,14 @@ std::vector<std::filesystem::path> WindowsPlatform::GetNewAPILayerJSONPaths() {
399397
}
400398

401399
std::expected<LoaderData, std::string> WindowsPlatform::GetLoaderData() {
400+
if (!mLoaderData) {
401+
mLoaderData = GetLoaderDataWithoutCache();
402+
}
403+
return mLoaderData.value();
404+
}
405+
406+
std::expected<LoaderData, std::string>
407+
WindowsPlatform::GetLoaderDataWithoutCache() {
402408
SECURITY_ATTRIBUTES saAttr {
403409
.nLength = sizeof(SECURITY_ATTRIBUTES),
404410
.bInheritHandle = TRUE,

src/windows/WindowsPlatform.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "CheckForUpdates.hpp"
1212
#include "Config.hpp"
13+
#include "LoaderData.hpp"
1314
#include "Platform.hpp"
1415

1516
namespace FredEmmott::OpenXRLayers {
@@ -25,7 +26,7 @@ class WindowsPlatform final : public Platform {
2526
return mDPIScaling;
2627
}
2728
void ShowFolderContainingFile(const std::filesystem::path& path) override;
28-
std::vector<std::string> GetEnvironmentVariableNames() override;
29+
std::unordered_set<std::string> GetEnvironmentVariableNames() override;
2930

3031
private:
3132
wil::unique_hwnd mWindowHandle {};
@@ -45,6 +46,7 @@ class WindowsPlatform final : public Platform {
4546
Config::MINIMUM_WINDOW_WIDTH,
4647
Config::MINIMUM_WINDOW_HEIGHT,
4748
};
49+
std::optional<std::expected<LoaderData, std::string>> mLoaderData;
4850

4951
HWND CreateAppWindow();
5052
void InitializeFonts(ImGuiIO* io);
@@ -57,6 +59,7 @@ class WindowsPlatform final : public Platform {
5759
void MainLoop(const std::function<void()>& drawFrame);
5860
void Shutdown();
5961

62+
static std::expected<LoaderData, std::string> GetLoaderDataWithoutCache();
6063
static LRESULT WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
6164

6265
LRESULT

0 commit comments

Comments
 (0)