mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-04 21:12:42 +08:00
[fix] avoid PRIME offload on NVIDIA primary displays, refs #137
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user