[platforms/virtual] Use rendernode or vgem device if available for egl

Summary:
The egl implementation for the virtual platform tries to use a render
node if available. If there is no render node it looks for a virtual
(kernel driver vgem) device, which unfortunately does not create a
render node in mainline kernel (there are patches in ChromiumOS).

For this the Udev wrapper is extended to search for renderNode devices
and for virtual dri devices.

If either render node or vgem dri device is found, it is tried to be
opened (without logind escalation) and on success a gbm device is
created on it. If any step of this fails the so far default behavior
of default device is tried for creating the EGLDisplay.

All of this is compile optional, so that the virtual platform does not
hard depend on udev and/or gbm.

Test Plan:
Auto tests which need OpenGL executed and verified that they
use the render node or vgem device.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D2216
icc-effect-5.14.5
Martin Gräßlin 2016-07-19 10:51:09 +02:00
parent 3308f35984
commit 56ce6689fd
7 changed files with 116 additions and 1 deletions

View File

@ -177,6 +177,10 @@ set(HAVE_INPUT FALSE)
if (Libinput_FOUND AND UDEV_FOUND)
set(HAVE_INPUT TRUE)
endif()
set(HAVE_UDEV FALSE)
if (UDEV_FOUND)
set(HAVE_UDEV TRUE)
endif()
find_package(Libdrm)
set_package_properties(Libdrm PROPERTIES TYPE OPTIONAL PURPOSE "Required for drm output on Wayland.")

View File

@ -21,6 +21,7 @@
#cmakedefine01 HAVE_SYS_PROCCTL_H
#cmakedefine01 HAVE_PROC_TRACE_CTL
#cmakedefine01 HAVE_BREEZE_DECO
#cmakedefine01 HAVE_UDEV
#if HAVE_BREEZE_DECO
#define BREEZE_KDECORATION_PLUGIN_ID "${BREEZE_KDECORATION_PLUGIN_ID}"
#endif

View File

@ -5,9 +5,16 @@ set(VIRTUAL_SOURCES
screens_virtual.cpp
)
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(VIRTUAL_SOURCES HEADER logging.h IDENTIFIER KWIN_VIRTUAL CATEGORY_NAME kwin_platform_virtual DEFAULT_SEVERITY Critical)
add_library(KWinWaylandVirtualBackend MODULE ${VIRTUAL_SOURCES})
target_link_libraries(KWinWaylandVirtualBackend kwin)
if(HAVE_GBM)
target_link_libraries(KWinWaylandVirtualBackend gbm::gbm)
endif()
install(
TARGETS
KWinWaylandVirtualBackend

View File

@ -23,10 +23,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "virtual_backend.h"
#include "options.h"
#include "screens.h"
#if HAVE_UDEV
#include "udev.h"
#endif
#include <logging.h>
// kwin libs
#include <kwinglplatform.h>
// Qt
#include <QOpenGLContext>
// system
#include <fcntl.h>
#include <unistd.h>
#if HAVE_GBM
#include <gbm.h>
#endif
namespace KWin
{
@ -48,6 +58,47 @@ EglGbmBackend::~EglGbmBackend()
delete m_fbo;
delete m_backBuffer;
cleanup();
#if HAVE_GBM
if (m_device) {
gbm_device_destroy(m_device);
}
#endif
if (m_drmFd != -1) {
close(m_drmFd);
}
}
void EglGbmBackend::initGbmDevice()
{
#if HAVE_UDEV
if (m_drmFd != -1) {
// already initialized
return;
}
QScopedPointer<Udev> udev(new Udev);
UdevDevice::Ptr device = udev->renderNode();
if (!device) {
// if we don't have a render node, try to find a virtual (vgem) device
qCDebug(KWIN_VIRTUAL) << "No render node, looking for a vgem device";
device = udev->virtualGpu();
}
if (!device) {
qCDebug(KWIN_VIRTUAL) << "Neither a render node, nor a vgem device found";
return;
}
qCDebug(KWIN_VIRTUAL) << "Found a device: " << device->devNode();
m_drmFd = open(device->devNode(), O_RDWR | O_CLOEXEC);
if (m_drmFd == -1) {
qCWarning(KWIN_VIRTUAL) << "Failed to open: " << device->devNode();
return;
}
#if HAVE_GBM
m_device = gbm_create_device(m_drmFd);
if (!m_device) {
qCWarning(KWIN_VIRTUAL) << "Failed to open gbm device";
}
#endif
#endif
}
bool EglGbmBackend::initializeEgl()
@ -64,7 +115,17 @@ bool EglGbmBackend::initializeEgl()
return false;
}
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, EGL_DEFAULT_DISPLAY, nullptr);
#if HAVE_GBM
initGbmDevice();
if (m_device) {
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, m_device, nullptr);
}
#endif
if (display == EGL_NO_DISPLAY) {
qCWarning(KWIN_VIRTUAL) << "Failed to create EGLDisplay through GBM device, trying with default device";
display = eglGetPlatformDisplay(EGL_PLATFORM_GBM_MESA, EGL_DEFAULT_DISPLAY, nullptr);
}
}
if (display == EGL_NO_DISPLAY)

View File

@ -21,6 +21,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KWIN_EGL_GBM_BACKEND_H
#include "abstract_egl_backend.h"
#include "scene_opengl.h"
#include <config-kwin.h>
#if HAVE_GBM
struct gbm_device;
#endif
namespace KWin
{
@ -51,10 +56,15 @@ private:
bool initializeEgl();
bool initBufferConfigs();
bool initRenderingContext();
void initGbmDevice();
VirtualBackend *m_backend;
GLTexture *m_backBuffer = nullptr;
GLRenderTarget *m_fbo = nullptr;
int m_frameCounter = 0;
#if HAVE_GBM
gbm_device *m_device = nullptr;
#endif
int m_drmFd = -1;
friend class EglGbmTexture;
};

View File

@ -148,6 +148,36 @@ UdevDevice::Ptr Udev::primaryGpu()
});
}
UdevDevice::Ptr Udev::virtualGpu()
{
if (!m_udev) {
return UdevDevice::Ptr();
}
UdevEnumerate enumerate(this);
enumerate.addMatch(UdevEnumerate::Match::SubSystem, "drm");
enumerate.addMatch(UdevEnumerate::Match::SysName, "card[0-9]*");
enumerate.scan();
return enumerate.find([](const UdevDevice::Ptr &device) {
const QByteArray deviceName(udev_device_get_syspath(*device));
return deviceName.contains("virtual");
});
}
UdevDevice::Ptr Udev::renderNode()
{
if (!m_udev) {
return UdevDevice::Ptr();
}
UdevEnumerate enumerate(this);
enumerate.addMatch(UdevEnumerate::Match::SubSystem, "drm");
enumerate.addMatch(UdevEnumerate::Match::SysName, "renderD[0-9]*");
enumerate.scan();
return enumerate.find([](const UdevDevice::Ptr &device) {
Q_UNUSED(device)
return true;
});
}
UdevDevice::Ptr Udev::deviceFromSyspath(const char *syspath)
{
return std::move(UdevDevice::Ptr(new UdevDevice(udev_device_new_from_syspath(m_udev, syspath))));

2
udev.h
View File

@ -83,6 +83,8 @@ public:
return m_udev != nullptr;
}
UdevDevice::Ptr primaryGpu();
UdevDevice::Ptr virtualGpu();
UdevDevice::Ptr renderNode();
UdevDevice::Ptr deviceFromSyspath(const char *syspath);
UdevMonitor *monitor();
operator udev*() const {