Skip to content

Commit

Permalink
Bug 1843782 - WebGL software rendering when mesa/vmwgfx driver detect…
Browse files Browse the repository at this point in the history
…ed r=jgilbert a=RyanVM

Original Revision: https://phabricator.services.mozilla.com/D192039

Differential Revision: https://phabricator.services.mozilla.com/D195330
  • Loading branch information
Ponchale committed Mar 6, 2024
1 parent d21b9ac commit 0b15f6c
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 4 deletions.
3 changes: 2 additions & 1 deletion gfx/config/gfxVars.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ class gfxVarReceiver;
_(AllowBackdropFilter, bool, true) \
_(WebglOopAsyncPresentForceSync, bool, true) \
_(UseAcceleratedCanvas2D, bool, false) \
_(UseWebRenderDCompSwVideoOverlayWin, bool, false)
_(UseWebRenderDCompSwVideoOverlayWin, bool, false) \
_(WebglUseHardware, bool, true)

/* Add new entries above this line. */

Expand Down
22 changes: 22 additions & 0 deletions gfx/gl/GLContextProviderEGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,28 @@ RefPtr<GLContextEGL> GLContextEGL::CreateWithoutSurface(
const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc,
nsACString* const out_failureId) {
const auto WithUseGles = [&](const bool useGles) -> RefPtr<GLContextEGL> {
#ifdef MOZ_WIDGET_GTK
// First try creating a context with no config and no surface, this is what
// we really want, and seems to be the only way to make selecting software
// Mesa init properly when it's not the first device.
if (egl->IsExtensionSupported(EGLExtension::KHR_no_config_context) &&
egl->IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
// These extensions have been supported by mesa and nvidia drivers
// since 2014 or earlier, this is the preferred code path
auto fullDesc = GLContextDesc{desc};
fullDesc.isOffscreen = true;
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
egl, fullDesc, EGL_NO_CONFIG, EGL_NO_SURFACE, useGles, EGL_NO_CONFIG,
out_failureId);
if (gl) {
return gl;
}
NS_WARNING(
"Failed to create GLContext with no config and no surface, will try "
"ChooseConfig");
}
#endif

const EGLConfig surfaceConfig = ChooseConfig(*egl, desc, useGles);
if (surfaceConfig == EGL_NO_CONFIG) {
*out_failureId = "FEATURE_FAILURE_EGL_NO_CONFIG"_ns;
Expand Down
47 changes: 45 additions & 2 deletions gfx/gl/GLLibraryEGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,44 @@ static std::shared_ptr<EglDisplay> GetAndInitDeviceDisplay(
return EglDisplay::Create(egl, display, true, aProofOfLock);
}

static std::shared_ptr<EglDisplay> GetAndInitSoftwareDisplay(
GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) {
if (!egl.IsExtensionSupported(EGLLibExtension::EXT_platform_device) ||
!egl.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration)) {
return nullptr;
}

EGLint maxDevices;
if (!egl.fQueryDevicesEXT(0, nullptr, &maxDevices)) {
return nullptr;
}

std::vector<EGLDeviceEXT> devices(maxDevices);
EGLint numDevices;
if (!egl.fQueryDevicesEXT(devices.size(), devices.data(), &numDevices)) {
return nullptr;
}
devices.resize(numDevices);

EGLDisplay display = EGL_NO_DISPLAY;
for (const auto& device : devices) {
const char* renderNodeString =
egl.fQueryDeviceStringEXT(device, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT);
// We are looking for a device with no file
if (!renderNodeString || *renderNodeString == 0) {
const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE};
display = egl.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, device,
attrib_list);
break;
}
}
if (!display) {
return nullptr;
}

return EglDisplay::Create(egl, display, true, aProofOfLock);
}

static std::shared_ptr<EglDisplay> GetAndInitSurfacelessDisplay(
GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) {
if (!egl.IsExtensionSupported(EGLLibExtension::MESA_platform_surfaceless)) {
Expand Down Expand Up @@ -904,12 +942,17 @@ std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplayLocked(
} else {
void* nativeDisplay = EGL_DEFAULT_DISPLAY;
#ifdef MOZ_WAYLAND
if (!gdk_display_get_default()) {
if (!ret && !gfx::gfxVars::WebglUseHardware()) {
// Initialize a swrast egl device such as llvmpipe
ret = GetAndInitSoftwareDisplay(*this, aProofOfLock);
}
// Initialize the display the normal way
if (!ret && !gdk_display_get_default()) {
ret = GetAndInitDeviceDisplay(*this, aProofOfLock);
if (!ret) {
ret = GetAndInitSurfacelessDisplay(*this, aProofOfLock);
}
} else if (widget::GdkIsWaylandDisplay()) {
} else if (!ret && widget::GdkIsWaylandDisplay()) {
// Wayland does not support EGL_DEFAULT_DISPLAY
nativeDisplay = widget::WaylandDisplayGetWLDisplay();
if (!nativeDisplay) {
Expand Down
2 changes: 2 additions & 0 deletions gfx/thebes/gfxPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2931,6 +2931,8 @@ void gfxPlatform::InitWebGLConfig() {
IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_OPENGL));
gfxVars::SetAllowWebglAccelAngle(
IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_ANGLE));
gfxVars::SetWebglUseHardware(
IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_USE_HARDWARE));

if (kIsMacOS) {
// Avoid crash for Intel HD Graphics 3000 on OSX. (Bug 1413269)
Expand Down
5 changes: 5 additions & 0 deletions gfx/thebes/gfxPlatformGtk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ bool gfxPlatformGtk::InitVAAPIConfig(bool aForceEnabledByUser) {
"FEATURE_FAILURE_REQUIRES_EGL"_ns);
}

if (!gfxVars::WebglUseHardware()) {
feature.Disable(FeatureStatus::Blocklisted,
"DMABuf disabled with software rendering", failureId);
}

// Configure zero-copy playback feature.
if (feature.IsEnabled()) {
FeatureState& featureZeroCopy =
Expand Down
4 changes: 4 additions & 0 deletions widget/GfxInfoBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/BuildConstants.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/gfxVars.h"
Expand Down Expand Up @@ -266,6 +267,9 @@ static const char* GetPrefNameForFeature(int32_t aFeature) {
case nsIGfxInfo::FEATURE_AV1_HW_DECODE:
name = BLOCKLIST_PREF_BRANCH "av1.hw-decode";
break;
case nsIGfxInfo::FEATURE_WEBGL_USE_HARDWARE:
name = BLOCKLIST_PREF_BRANCH "webgl-use-hardware";
break;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!");
break;
Expand Down
8 changes: 8 additions & 0 deletions widget/gtk/GfxInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,14 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0),
"FEATURE_FAILURE_WEBRENDER_MESA_VM", "");

// Disable hardware mesa drivers in virtual machines due to instability.
APPEND_TO_DRIVER_BLOCKLIST_EXT(
OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
WindowProtocol::All, DriverVendor::MesaVM, DeviceFamily::All,
nsIGfxInfo::FEATURE_WEBGL_USE_HARDWARE,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
V(0, 0, 0, 0), "FEATURE_FAILURE_WEBGL_MESA_VM", "");

////////////////////////////////////
// FEATURE_WEBRENDER_COMPOSITOR
Expand Down
4 changes: 3 additions & 1 deletion widget/nsIGfxInfo.idl
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,10 @@ interface nsIGfxInfo : nsISupports
const long FEATURE_H264_HW_DECODE = 44;
/* Whether hardware AV1 decoding is supported, starting in 114; not for downloadable blocking. */
const long FEATURE_AV1_HW_DECODE = 45;
/* Whether WebGL is allowed to use hardware rendering, otherwise software fallbacks. */
const long FEATURE_WEBGL_USE_HARDWARE = 46;
/* the maximum feature value. */
const long FEATURE_MAX_VALUE = FEATURE_ACCELERATED_CANVAS2D;
const long FEATURE_MAX_VALUE = FEATURE_WEBGL_USE_HARDWARE;

/*
* A set of return values from GetFeatureStatus
Expand Down

0 comments on commit 0b15f6c

Please sign in to comment.