10#include "compositor.h"
24#include <QOpenGLContext>
28#include <drm_fourcc.h>
34static std::unique_ptr<EglContext> s_globalShareContext;
36static bool isOpenGLES_helper()
38 if (qstrcmp(qgetenv(
"KWIN_COMPOSE"),
"O2ES") == 0) {
41 return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES;
45 : m_deviceId(deviceId)
56 if (!s_globalShareContext) {
59 if (s_globalShareContext) {
60 kwinApp()->outputBackend()->setSceneEglGlobalShareContext(s_globalShareContext->handle());
69 EglDisplay *
const eglDisplay = kwinApp()->outputBackend()->sceneEglDisplayObject();
70 if (!eglDisplay || !s_globalShareContext) {
73 s_globalShareContext.reset();
74 kwinApp()->outputBackend()->setSceneEglGlobalShareContext(EGL_NO_CONTEXT);
109static eglFuncPtr getProcAddress(
const char *name)
111 return eglGetProcAddress(name);
124 if (!WaylandServer::self()) {
130 if (renderNode.isEmpty()) {
131 drmDevice *device =
nullptr;
132 if (drmGetDeviceFromDevId(
deviceId(), 0, &device) != 0) {
133 qCWarning(KWIN_OPENGL) <<
"drmGetDeviceFromDevId() failed:" << strerror(errno);
135 if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
136 renderNode = QString::fromLocal8Bit(device->nodes[DRM_NODE_RENDER]);
137 }
else if (device->available_nodes & (1 << DRM_NODE_PRIMARY)) {
138 qCWarning(KWIN_OPENGL) <<
"No render nodes have been found, falling back to primary node";
139 renderNode = QString::fromLocal8Bit(device->nodes[DRM_NODE_PRIMARY]);
141 drmFreeDevice(&device);
145 if (!renderNode.isEmpty()) {
148 qCWarning(KWIN_OPENGL) <<
"No render node have been found, not initializing wl-drm";
153 auto filterFormats = [
this, &formats](std::optional<uint32_t> bpc,
bool withExternalOnlyYUV) {
154 QHash<uint32_t, QList<uint64_t>> set;
155 for (
auto it = formats.constBegin(); it != formats.constEnd(); it++) {
157 if (!info || (bpc && bpc != info->bitsPerColor)) {
161 const bool externalOnlySupported = withExternalOnlyYUV && info->yuvConversion();
162 QList<uint64_t> modifiers = externalOnlySupported ? it->allModifiers : it->nonExternalOnlyModifiers;
164 if (externalOnlySupported && !modifiers.isEmpty()) {
165 if (
auto yuv = info->yuvConversion()) {
166 for (
auto plane : std::as_const(yuv->plane)) {
167 const auto planeModifiers = formats.value(plane.format).allModifiers;
168 modifiers.erase(std::remove_if(modifiers.begin(), modifiers.end(), [&planeModifiers](uint64_t mod) {
169 return !planeModifiers.contains(mod);
175 for (
const auto &tranche : std::as_const(
m_tranches)) {
176 if (modifiers.isEmpty()) {
179 const auto trancheModifiers = tranche.formatTable.value(it.key());
180 for (
auto trancheModifier : trancheModifiers) {
181 modifiers.removeAll(trancheModifier);
184 if (modifiers.isEmpty()) {
187 set.insert(it.key(), modifiers);
192 auto includeShaderConversions = [](QHash<uint32_t, QList<uint64_t>> &&formats) -> QHash<uint32_t, QList<uint64_t>> {
193 for (
auto format : s_drmConversions.keys()) {
194 auto &modifiers = formats[
format];
195 if (modifiers.isEmpty()) {
196 modifiers = {DRM_FORMAT_MOD_LINEAR};
206 .formatTable = filterFormats(10,
false),
212 .formatTable = filterFormats(8,
false),
217 .formatTable = includeShaderConversions(filterFormats({},
true)),
228 const char *clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
229 const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString));
230 if (clientExtensionsString.isEmpty()) {
246 if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
248 context->doneCurrent();
260 return isOpenGLES_helper();
294 std::pair key(buffer, plane);
302 if (image != EGL_NO_IMAGE_KHR) {
304 connect(buffer, &QObject::destroyed,
this, [
this, key]() {
308 qCWarning(KWIN_OPENGL) <<
"failed to import dmabuf" << buffer;
316 auto key = std::pair(buffer, 0);
324 if (image != EGL_NO_IMAGE_KHR) {
326 connect(buffer, &QObject::destroyed,
this, [
this, key]() {
330 qCWarning(KWIN_OPENGL) <<
"failed to import dmabuf" << buffer;
348 return m_context->importDmaBufAsTexture(attributes);
382#include "moc_abstract_egl_backend.cpp"
void initClientExtensions()
EGLSurface surface() const
virtual void cleanupSurfaces()
bool makeCurrent() override
bool hasClientExtension(const QByteArray &ext) const
EglDisplay * eglDisplayObject() const
QList< LinuxDmaBufV1Feedback::Tranche > tranches() const
void setEglDisplay(EglDisplay *display)
EGLImageKHR importBufferAsImage(GraphicsBuffer *buffer)
QHash< std::pair< GraphicsBuffer *, int >, EGLImageKHR > m_importedBuffers
void doneCurrent() override
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &attributes) const
QList< LinuxDmaBufV1Feedback::Tranche > m_tranches
std::shared_ptr< GLTexture > importDmaBufAsTexture(const DmaBufAttributes &attributes) const
bool ensureGlobalShareContext(EGLConfig config)
EglContext * contextObject()
QHash< uint32_t, QList< uint64_t > > supportedFormats() const override
void setSurface(const EGLSurface &surface)
virtual bool prefer10bpc() const
bool createContext(EGLConfig config)
std::shared_ptr< EglContext > m_context
~AbstractEglBackend() override
void destroyGlobalShareContext()
bool testImportBuffer(GraphicsBuffer *buffer) override
QList< QByteArray > m_clientExtensions
AbstractEglBackend(dev_t deviceId=0)
static Compositor * self()
void setDevice(const QString &node)
static std::unique_ptr< EglContext > create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
QString renderNode() const
bool supportsNativeFence() const
QList< QByteArray > extensions() const
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const
QHash< uint32_t, QList< uint64_t > > nonExternalOnlySupportedDrmFormats() const
QHash< uint32_t, DrmFormatInfo > allSupportedDrmFormats() const
bool supportsBufferAge() const
::EGLDisplay handle() const
virtual const DmaBufAttributes * dmabufAttributes() const
void setSupportedFormatsWithModifiers(const QList< LinuxDmaBufV1Feedback::Tranche > &tranches)
void setRenderBackend(RenderBackend *renderBackend)
void setSupportsBufferAge(bool value)
void setSupportsNativeFence(bool value)
void setExtensions(const QList< QByteArray > &extensions)
LinuxDmaBufV1ClientBufferIntegration * linuxDmabuf()
DrmClientBufferIntegration * drm()
void KWIN_EXPORT cleanupGL()
void initGL(const std::function< resolveFuncPtr(const char *)> &resolveFunction)
WaylandServer * waylandServer()