Merge pull request #1413 from HifiExperiments/driverBlocklist

add GPU driver blocklist
This commit is contained in:
Julian Groß 2025-06-15 09:06:35 +02:00 committed by GitHub
commit 6aa7030af3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 124 additions and 1 deletions

View file

@ -42,6 +42,7 @@
#include <DomainAccountManager.h> #include <DomainAccountManager.h>
#include <EntityScriptServerLogClient.h> #include <EntityScriptServerLogClient.h>
#include <FramebufferCache.h> #include <FramebufferCache.h>
#include <gl/GLHelpers.h>
#include <GPUIdent.h> #include <GPUIdent.h>
#include <graphics-scripting/GraphicsScriptingInterface.h> #include <graphics-scripting/GraphicsScriptingInterface.h>
#include <hfm/ModelFormatRegistry.h> #include <hfm/ModelFormatRegistry.h>
@ -56,6 +57,9 @@
#include <networking/CloseEventSender.h> #include <networking/CloseEventSender.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
#include <PickManager.h> #include <PickManager.h>
#include <platform/Platform.h>
#include <platform/PlatformKeys.h>
#include <platform/backend/PlatformInstance.h>
#include <plugins/OculusPlatformPlugin.h> #include <plugins/OculusPlatformPlugin.h>
#include <plugins/PluginManager.h> #include <plugins/PluginManager.h>
#include <plugins/PluginUtils.h> #include <plugins/PluginUtils.h>
@ -1890,13 +1894,32 @@ void Application::idle() {
_gameLoopCounter.increment(); _gameLoopCounter.increment();
// Perform one-time startup checks in case we need to show warnings
{ {
static std::once_flag once; static std::once_flag once;
std::call_once(once, [] { std::call_once(once, [this] {
const QString& bookmarksError = DependencyManager::get<AvatarBookmarks>()->getBookmarkError(); const QString& bookmarksError = DependencyManager::get<AvatarBookmarks>()->getBookmarkError();
if (!bookmarksError.isEmpty()) { if (!bookmarksError.isEmpty()) {
OffscreenUi::asyncWarning("Avatar Bookmarks Error", "JSON parse error: " + bookmarksError, QMessageBox::Ok, QMessageBox::Ok); OffscreenUi::asyncWarning("Avatar Bookmarks Error", "JSON parse error: " + bookmarksError, QMessageBox::Ok, QMessageBox::Ok);
} }
QString os = platform::getComputer()[platform::keys::computer::OS].dump().c_str();
os = os.replace("\"", "");
GPUIdent* gpuIdent = GPUIdent::getInstance();
QString vendor = platform::Instance::findGPUVendorInDescription(gpuIdent->getName().toStdString());
QString renderer = gl::ContextInfo::get().renderer.c_str();
QString api = _graphicsEngine->getGPUContext()->getBackendVersion().c_str();
QString driver = gpuIdent->getDriver();
QString fullDriverToTest = os + " " + vendor + " " + renderer + " " + api + " " + driver;
if (fullDriverToTest != _prevCheckedDriver.get()) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(QUrl("https://mv.overte.org/gpu_driver_blocklist.json"));
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::OVERTE_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(request);
auto onFinished = std::bind(&Application::processDriverBlocklistReply, this, fullDriverToTest, os, vendor, renderer, api, driver.replace(" ", "."));
connect(reply, &QNetworkReply::finished, this, onFinished);
}
}); });
} }
} }

View file

@ -655,6 +655,9 @@ private:
bool handleKeyEventForFocusedEntity(QEvent* event); bool handleKeyEventForFocusedEntity(QEvent* event);
bool handleFileOpenEvent(QFileOpenEvent* event); bool handleFileOpenEvent(QFileOpenEvent* event);
void processDriverBlocklistReply(const QString& fullDriverToTest, const QString& os, const QString& vendor, const QString& renderer, const QString& api,
const QString& driver);
// Entities // Entities
void queryOctree(NodeType_t serverType, PacketType packetType); void queryOctree(NodeType_t serverType, PacketType packetType);
@ -906,6 +909,7 @@ private:
std::shared_ptr<GraphicsEngine> _graphicsEngine; std::shared_ptr<GraphicsEngine> _graphicsEngine;
glm::uvec2 _renderResolution; glm::uvec2 _renderResolution;
Setting::Handle<QString> _prevCheckedDriver { "prevCheckedDriver", "" };
bool _isGLInitialized { false }; bool _isGLInitialized { false };

View file

@ -929,3 +929,99 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) {
} }
return false; return false;
} }
void Application::processDriverBlocklistReply(const QString& fullDriverToTest, const QString& os, const QString& vendor, const QString& renderer, const QString& api,
const QString& driver) {
// The driver blocklist is a JSON array of objects where each object contains:
// - os (e.g. Windows, Linux): The system OS
// - vendor (e.g. NVIDIA, AMD): The GPU maker
// - renderer (optional) (e.g. AMD, Panfrost): The driver stack, if specified
// - api (e.g GL45, GLES): The backend version
// - version (optional) (e.g. 32.0.15.6070): The driver version, if just a single version is problematic
// - first_version (optional) (e.g. 32.0.15.6070): If a range is problematic, the first problematic version
// - last_version (optional) (e.g. 32.0.15.6070): If a range is problematic, the final problematic version. If this is not provided,
// all versions above first_version will trigger a warning.
// - description: Description of the issue.
// String values are *case insensitive*
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
QByteArray data = reply->readAll();
QJsonParseError error;
QJsonDocument json = QJsonDocument::fromJson(data, &error);
if (json.isNull() || !json.isArray()) {
OffscreenUi::asyncWarning("Driver Blocklist Error", "There is a problem with the GPU driver blocklist: " + error.errorString(),
QMessageBox::Ok, QMessageBox::Ok);
}
_prevCheckedDriver.set(fullDriverToTest);
QJsonArray driverArray = json.array();
for (QJsonValueRef driverJSON : driverArray) {
if (!driverJSON.isObject()) {
continue;
}
QJsonObject driverObject = driverJSON.toObject();
if (os.toLower() != driverObject["os"].toString().toLower()) {
continue;
}
if (vendor.toLower() != driverObject["vendor"].toString().toLower()) {
continue;
}
if (driverObject.contains("renderer")) {
if (renderer.toLower().contains(driverObject["renderer"].toString().toLower())) {
continue;
}
}
if (api.toLower() != driverObject["api"].toString().toLower()) {
continue;
}
QString minDriver;
QString maxDriver;
if (driverObject.contains("version")) {
QString driverString = driverObject["version"].toString();
minDriver = driverString;
maxDriver = driverString;
} else {
minDriver = driverObject["first_version"].toString();
if (driverObject.contains("last_version")) {
QString driverString = driverObject["last_version"].toString();
maxDriver = driverString;
}
}
minDriver = minDriver.replace(" ", ".");
maxDriver = maxDriver.replace(" ", ".");
const auto compareDriver = [] (const QStringList& driver1, const QStringList& driver2, std::function<bool(int, int)> func) {
if (driver1.size() != driver2.size()) {
return false;
}
for (size_t i = 0; i < driver1.size(); i++) {
if (!func(driver1[i].toInt(), driver2[i].toInt())) {
return false;
}
}
return true;
};
QStringList driverParts = driver.split(".");
bool inErrorRange = compareDriver(driverParts, minDriver.split("."), [] (int driverPart1, int driverPart2) { return driverPart1 >= driverPart2; });
if (!maxDriver.isEmpty()) {
inErrorRange &= compareDriver(driverParts, maxDriver.split("."), [] (int driverPart1, int driverPart2) { return driverPart1 <= driverPart2; });
}
if (inErrorRange) {
QString issue = driverObject["description"].toString();
OffscreenUi::asyncWarning(
"GPU Driver Warning", "Your GPU driver (" + driver + ") has been reported as problematic (Issue: " + issue + "). If you encounter issues, consider trying a different version.",
QMessageBox::Ok, QMessageBox::Ok);
break;
}
}
}