[fix] avoid PRIME offload on NVIDIA primary displays, refs #137

This commit is contained in:
dijunkun
2026-11-04 12:29:34 +08:00
parent 2fab61871e
commit 049cc0c8de
4 changed files with 218 additions and 2 deletions
@@ -2,12 +2,62 @@
#include <cstdlib>
#include <initializer_list>
#include <memory>
#include <string_view>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include "rd_log.h"
#include "platform/common/gui/cuda_opengl_interop.h"
namespace crossdesk {
namespace {
#if USE_CUDA && (defined(__x86_64__) || defined(__amd64__))
bool HasNvidiaOffloadProvider() {
// CUDA availability says nothing about the X server's PRIME topology.
// In particular, NVIDIA-0 is a normal display provider, not an offload
// GPU screen. Forcing offload in that configuration can render into a GL
// buffer successfully while leaving the actual window blank.
const char* display_name = std::getenv("DISPLAY");
if (!display_name || display_name[0] == '\0') return false;
std::unique_ptr<Display, decltype(&XCloseDisplay)> display(
XOpenDisplay(display_name), XCloseDisplay);
if (!display) return false;
int major = 0, minor = 0;
if (!XRRQueryVersion(display.get(), &major, &minor) || major < 1 ||
(major == 1 && minor < 4)) return false;
const auto root = XDefaultRootWindow(display.get());
std::unique_ptr<XRRScreenResources, decltype(&XRRFreeScreenResources)> screen(
XRRGetScreenResourcesCurrent(display.get(), root), XRRFreeScreenResources);
std::unique_ptr<XRRProviderResources, decltype(&XRRFreeProviderResources)>
providers(XRRGetProviderResources(display.get(), root),
XRRFreeProviderResources);
if (!screen || !providers) return false;
for (int i = 0; i < providers->nproviders; ++i) {
std::unique_ptr<XRRProviderInfo, decltype(&XRRFreeProviderInfo)> provider(
XRRGetProviderInfo(display.get(), screen.get(), providers->providers[i]),
XRRFreeProviderInfo);
if (!provider || !provider->name || provider->nameLen <= 0) continue;
const std::string_view name(provider->name, provider->nameLen);
// NVIDIA documents offload GPU screens as NVIDIA-G0, NVIDIA-G1, etc.
// Their RandR capability mask can be zero, so SourceOffload is not a
// reliable test for the proprietary driver's offload support.
constexpr std::string_view prefix = "NVIDIA-G";
if (name.size() > prefix.size() && name.substr(0, prefix.size()) == prefix &&
name.find_first_not_of("0123456789", prefix.size()) ==
std::string_view::npos) return true;
}
return false;
}
#endif
} // namespace
void ConfigureLinuxCudaGraphics() {
#if USE_CUDA && (defined(__x86_64__) || defined(__amd64__))
@@ -28,6 +78,11 @@ void ConfigureLinuxCudaGraphics() {
}
}
if (!HasNvidiaOffloadProvider()) {
LOG_INFO("Keeping default Linux graphics selection: no NVIDIA PRIME "
"offload GPU screen");
return;
}
if (!IsCudaDeviceAvailable()) {
return;
}