diff --git a/CMakeLists.txt b/CMakeLists.txt index 12946ae950..7d17adb89c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,11 +230,6 @@ else() set(HAVE_GBM_BO_GET_FD_FOR_PLANE 0) endif() -option(KWIN_BUILD_EGL_STREAM_BACKEND "Enable building of EGLStream based DRM backend" ON) -if (KWIN_BUILD_EGL_STREAM_BACKEND) - set(HAVE_EGL_STREAMS TRUE) -endif() - find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" diff --git a/src/backends/drm/CMakeLists.txt b/src/backends/drm/CMakeLists.txt index cd9d0f5a07..35ff2f2999 100644 --- a/src/backends/drm/CMakeLists.txt +++ b/src/backends/drm/CMakeLists.txt @@ -30,12 +30,6 @@ if (HAVE_GBM) ) endif() -if (HAVE_EGL_STREAMS) - set(DRM_SOURCES ${DRM_SOURCES} - egl_stream_backend.cpp - ) -endif() - add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES}) set_target_properties(KWinWaylandDrmBackend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.waylandbackends/") target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm) diff --git a/src/backends/drm/drm_backend.cpp b/src/backends/drm/drm_backend.cpp index 238d4b6587..b36c974042 100644 --- a/src/backends/drm/drm_backend.cpp +++ b/src/backends/drm/drm_backend.cpp @@ -31,9 +31,6 @@ #include #include "gbm_dmabuf.h" #endif -#if HAVE_EGL_STREAMS -#include "egl_stream_backend.h" -#endif // KF5 #include #include @@ -190,17 +187,6 @@ bool DrmBackend::initialize() bootVga |= device->isBootVga(); } } - - // if a boot device is set, honor that setting - // if not, prefer gbm for rendering because that works better - if (!bootVga && !m_gpus.isEmpty() && m_gpus[0]->useEglStreams()) { - for (int i = 1; i < m_gpus.count(); i++) { - if (!m_gpus[i]->useEglStreams()) { - m_gpus.swapItemsAt(i, 0); - break; - } - } - } } if (m_gpus.isEmpty()) { @@ -209,10 +195,6 @@ bool DrmBackend::initialize() } initCursor(); - // workaround for BUG 438363: something goes wrong in scene initialization without a surface being current in EglStreamBackend - if (m_gpus[0]->useEglStreams()) { - updateOutputs(); - } // setup udevMonitor if (m_udevMonitor) { @@ -276,9 +258,6 @@ void DrmBackend::handleUdevEvent() DrmGpu *DrmBackend::addGpu(const QString &fileName) { - if (primaryGpu() && primaryGpu()->useEglStreams()) { - return nullptr; - } int fd = session()->openRestricted(fileName); if (fd < 0) { qCWarning(KWIN_DRM) << "failed to open drm device at" << fileName; @@ -519,21 +498,6 @@ void DrmBackend::enableOutput(DrmAbstractOutput *output, bool enable) void DrmBackend::initCursor() { - -#if HAVE_EGL_STREAMS - // Hardware cursors aren't currently supported with EGLStream backend, - // possibly an NVIDIA driver bug - bool needsSoftwareCursor = false; - for (auto gpu : qAsConst(m_gpus)) { - if (gpu->useEglStreams()) { - needsSoftwareCursor = true; - break; - } - } - setSoftwareCursorForced(needsSoftwareCursor); -#endif - - // now we have screens and can set cursors, so start tracking connect(Cursors::self(), &Cursors::currentCursorChanged, this, &DrmBackend::updateCursor); connect(Cursors::self(), &Cursors::positionChanged, this, &DrmBackend::moveCursor); } @@ -623,14 +587,6 @@ QPainterBackend *DrmBackend::createQPainterBackend() OpenGLBackend *DrmBackend::createOpenGLBackend() { -#if HAVE_EGL_STREAMS - if (m_gpus.at(0)->useEglStreams()) { - auto backend = new EglStreamBackend(this, m_gpus.at(0)); - AbstractEglBackend::setPrimaryBackend(backend); - return backend; - } -#endif - #if HAVE_GBM auto primaryBackend = new EglGbmBackend(this, m_gpus.at(0)); AbstractEglBackend::setPrimaryBackend(primaryBackend); @@ -656,10 +612,6 @@ QVector DrmBackend::supportedCompositors() const } #if HAVE_GBM return QVector{OpenGLCompositing, QPainterCompositing}; -#elif HAVE_EGL_STREAMS - return m_gpus.at(0)->useEglStreams() ? - QVector{OpenGLCompositing, QPainterCompositing} : - QVector{QPainterCompositing}; #else return QVector{QPainterCompositing}; #endif @@ -675,9 +627,6 @@ QString DrmBackend::supportInformation() const for (int g = 0; g < m_gpus.size(); g++) { s << "Atomic Mode Setting on GPU " << g << ": " << m_gpus.at(g)->atomicModeSetting() << Qt::endl; } -#if HAVE_EGL_STREAMS - s << "Using EGL Streams: " << m_gpus.at(0)->useEglStreams() << Qt::endl; -#endif return supportInfo; } diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index a86f169b77..7eac50fd85 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -80,16 +80,8 @@ DrmGpu::DrmGpu(DrmBackend *backend, const QString &devNode, int fd, dev_t device // find out if this GPU is using the NVidia proprietary driver DrmScopedPointer version(drmGetVersion(fd)); m_isNVidia = strstr(version->name, "nvidia-drm"); - m_useEglStreams = m_isNVidia; #if HAVE_GBM m_gbmDevice = gbm_create_device(m_fd); - bool envVarIsSet = false; - bool value = qEnvironmentVariableIntValue("KWIN_DRM_FORCE_EGL_STREAMS", &envVarIsSet) != 0; - if (envVarIsSet) { - m_useEglStreams = m_isNVidia && value; - } else if (m_gbmDevice) { - m_useEglStreams = m_isNVidia && strcmp(gbm_device_get_backend_name(m_gbmDevice), "nvidia") != 0; - } #endif m_socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); @@ -695,11 +687,6 @@ bool DrmGpu::atomicModeSetting() const return m_atomicModeSetting; } -bool DrmGpu::useEglStreams() const -{ - return m_useEglStreams; -} - QString DrmGpu::devNode() const { return m_devNode; diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h index 09223744d7..ab7719991c 100644 --- a/src/backends/drm/drm_gpu.h +++ b/src/backends/drm/drm_gpu.h @@ -54,7 +54,6 @@ public: bool atomicModeSetting() const; bool addFB2ModifiersSupported() const; - bool useEglStreams() const; bool isNVidia() const; bool isFormatSupported(uint32_t drmFormat) const; gbm_device *gbmDevice() const; @@ -112,7 +111,6 @@ private: const dev_t m_deviceId; const QString m_devNode; bool m_atomicModeSetting; - bool m_useEglStreams; bool m_addFB2ModifiersSupported = false; bool m_isNVidia; clockid_t m_presentationClock; diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 6dc7f96192..8eda772ee4 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -62,13 +62,6 @@ bool DrmPipeline::present(const QSharedPointer &buffer) return false; } m_primaryBuffer = buffer; - if (gpu()->useEglStreams() && gpu()->eglBackend() != nullptr && gpu() == gpu()->platform()->primaryGpu()) { - // EglStreamBackend queues normal page flips through EGL, - // modesets etc are performed through DRM-KMS - if (!m_connector->needsCommit() && !pending.crtc->needsCommit()) { - return true; - } - } bool directScanout = false; #if HAVE_GBM // with direct scanout disallow modesets, calling presentFailed() and logging warnings @@ -254,8 +247,7 @@ bool DrmPipeline::populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags) prepareModeset(); flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; } - bool usesEglStreams = gpu()->useEglStreams() && gpu()->eglBackend() != nullptr && gpu() == gpu()->platform()->primaryGpu(); - if (!usesEglStreams && activePending()) { + if (activePending()) { flags |= DRM_MODE_PAGE_FLIP_EVENT; } if (pending.crtc) { diff --git a/src/backends/drm/egl_multi_backend.cpp b/src/backends/drm/egl_multi_backend.cpp index bc481b750a..234c1cd3de 100644 --- a/src/backends/drm/egl_multi_backend.cpp +++ b/src/backends/drm/egl_multi_backend.cpp @@ -13,9 +13,6 @@ #if HAVE_GBM #include "egl_gbm_backend.h" #endif -#if HAVE_EGL_STREAMS -#include "egl_stream_backend.h" -#endif #include "drm_backend.h" #include "drm_gpu.h" @@ -115,22 +112,13 @@ bool EglMultiBackend::directScanoutAllowed(AbstractOutput *output) const void EglMultiBackend::addGpu(DrmGpu *gpu) { - AbstractEglDrmBackend *backend; - if (gpu->useEglStreams()) { -#if HAVE_EGL_STREAMS - backend = new EglStreamBackend(m_platform, gpu); -#endif - } else { #if HAVE_GBM - backend = new EglGbmBackend(m_platform, gpu); + AbstractEglDrmBackend *backend= new EglGbmBackend(m_platform, gpu); + if (m_initialized) { + backend->init(); + } + m_backends.append(backend); #endif - } - if (backend) { - if (m_initialized) { - backend->init(); - } - m_backends.append(backend); - } } void EglMultiBackend::removeGpu(DrmGpu *gpu) diff --git a/src/backends/drm/egl_stream_backend.cpp b/src/backends/drm/egl_stream_backend.cpp deleted file mode 100644 index 1015c1e095..0000000000 --- a/src/backends/drm/egl_stream_backend.cpp +++ /dev/null @@ -1,783 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2019 NVIDIA Inc. - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "egl_stream_backend.h" -#include "basiceglsurfacetexture_internal.h" -#include "composite.h" -#include "drm_backend.h" -#include "drm_output.h" -#include "drm_object_crtc.h" -#include "drm_object_plane.h" -#include "logging.h" -#include "options.h" -#include "renderloop_p.h" -#include "scene.h" -#include "screens.h" -#include "surfaceitem_wayland.h" -#include "wayland_server.h" -#include -#include -#include "drm_gpu.h" -#include "dumb_swapchain.h" -#include "kwineglutils_p.h" -#include "shadowbuffer.h" -#include "drm_pipeline.h" - -#include -#include -#include -#include -#include - -namespace KWin -{ - -typedef EGLStreamKHR (*PFNEGLCREATESTREAMATTRIBNV)(EGLDisplay, EGLAttrib *); -typedef EGLBoolean (*PFNEGLGETOUTPUTLAYERSEXT)(EGLDisplay, EGLAttrib *, EGLOutputLayerEXT *, EGLint, EGLint *); -typedef EGLBoolean (*PFNEGLSTREAMCONSUMEROUTPUTEXT)(EGLDisplay, EGLStreamKHR, EGLOutputLayerEXT); -typedef EGLSurface (*PFNEGLCREATESTREAMPRODUCERSURFACEKHR)(EGLDisplay, EGLConfig, EGLStreamKHR, EGLint *); -typedef EGLBoolean (*PFNEGLDESTROYSTREAMKHR)(EGLDisplay, EGLStreamKHR); -typedef EGLBoolean (*PFNEGLSTREAMCONSUMERACQUIREATTRIBNV)(EGLDisplay, EGLStreamKHR, EGLAttrib *); -typedef EGLBoolean (*PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHR)(EGLDisplay, EGLStreamKHR); -typedef EGLBoolean (*PFNEGLQUERYSTREAMATTRIBNV)(EGLDisplay, EGLStreamKHR, EGLenum, EGLAttrib *); -typedef EGLBoolean (*PFNEGLSTREAMCONSUMERRELEASEKHR)(EGLDisplay, EGLStreamKHR); -typedef EGLBoolean (*PFNEGLQUERYWAYLANDBUFFERWL)(EGLDisplay, wl_resource *, EGLint, EGLint *); -PFNEGLCREATESTREAMATTRIBNV pEglCreateStreamAttribNV = nullptr; -PFNEGLGETOUTPUTLAYERSEXT pEglGetOutputLayersEXT = nullptr; -PFNEGLSTREAMCONSUMEROUTPUTEXT pEglStreamConsumerOutputEXT = nullptr; -PFNEGLCREATESTREAMPRODUCERSURFACEKHR pEglCreateStreamProducerSurfaceKHR = nullptr; -PFNEGLDESTROYSTREAMKHR pEglDestroyStreamKHR = nullptr; -PFNEGLSTREAMCONSUMERACQUIREATTRIBNV pEglStreamConsumerAcquireAttribNV = nullptr; -PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHR pEglStreamConsumerGLTextureExternalKHR = nullptr; -PFNEGLQUERYSTREAMATTRIBNV pEglQueryStreamAttribNV = nullptr; -PFNEGLSTREAMCONSUMERRELEASEKHR pEglStreamConsumerReleaseKHR = nullptr; -PFNEGLQUERYWAYLANDBUFFERWL pEglQueryWaylandBufferWL = nullptr; - -#ifndef EGL_CONSUMER_AUTO_ACQUIRE_EXT -#define EGL_CONSUMER_AUTO_ACQUIRE_EXT 0x332B -#endif - -#ifndef EGL_DRM_MASTER_FD_EXT -#define EGL_DRM_MASTER_FD_EXT 0x333C -#endif - -#ifndef EGL_DRM_FLIP_EVENT_DATA_NV -#define EGL_DRM_FLIP_EVENT_DATA_NV 0x333E -#endif - -#ifndef EGL_WAYLAND_EGLSTREAM_WL -#define EGL_WAYLAND_EGLSTREAM_WL 0x334B -#endif - -#ifndef EGL_WAYLAND_Y_INVERTED_WL -#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB -#endif - -EglStreamBackend::EglStreamBackend(DrmBackend *drmBackend, DrmGpu *gpu) - : AbstractEglDrmBackend(drmBackend, gpu) -{ -} - -EglStreamBackend::~EglStreamBackend() -{ - cleanup(); -} - -void EglStreamBackend::cleanupSurfaces() -{ - for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { - cleanupOutput(*it); - } - m_outputs.clear(); -} - -void EglStreamBackend::cleanupOutput(Output &o) -{ - if (o.eglSurface != EGL_NO_SURFACE) { - eglDestroySurface(eglDisplay(), o.eglSurface); - } - if (o.eglStream != EGL_NO_STREAM_KHR) { - pEglDestroyStreamKHR(eglDisplay(), o.eglStream); - } - o.shadowBuffer = nullptr; -} - -bool EglStreamBackend::initializeEgl() -{ - initClientExtensions(); - EGLDisplay display = m_gpu->eglDisplay(); - if (display == EGL_NO_DISPLAY) { - if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_device_base")) && - !(hasClientExtension(QByteArrayLiteral("EGL_EXT_device_query")) && - hasClientExtension(QByteArrayLiteral("EGL_EXT_device_enumeration")))) { - setFailed("Missing required EGL client extension: " - "EGL_EXT_device_base or " - "EGL_EXT_device_query and EGL_EXT_device_enumeration"); - return false; - } - - // Try to find the EGLDevice corresponding to our DRM device file - int numDevices; - eglQueryDevicesEXT(0, nullptr, &numDevices); - QVector devices(numDevices); - eglQueryDevicesEXT(numDevices, devices.data(), &numDevices); - for (EGLDeviceEXT device : devices) { - const char *drmDeviceFile = eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT); - if (m_gpu->devNode().compare(drmDeviceFile)) { - continue; - } - - const char *deviceExtensionCString = eglQueryDeviceStringEXT(device, EGL_EXTENSIONS); - QByteArray deviceExtensions = QByteArray::fromRawData(deviceExtensionCString, - qstrlen(deviceExtensionCString)); - if (!deviceExtensions.split(' ').contains(QByteArrayLiteral("EGL_EXT_device_drm"))) { - continue; - } - - EGLint platformAttribs[] = { - EGL_DRM_MASTER_FD_EXT, m_gpu->fd(), - EGL_NONE - }; - display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, device, platformAttribs); - break; - } - m_gpu->setEglDisplay(display); - } - - if (display == EGL_NO_DISPLAY) { - setFailed("No suitable EGL device found"); - return false; - } - - setEglDisplay(display); - if (!initEglAPI()) { - return false; - } - - const QVector requiredExtensions = { - QByteArrayLiteral("EGL_EXT_output_base"), - QByteArrayLiteral("EGL_EXT_output_drm"), - QByteArrayLiteral("EGL_KHR_stream"), - QByteArrayLiteral("EGL_KHR_stream_producer_eglsurface"), - QByteArrayLiteral("EGL_EXT_stream_consumer_egloutput"), - QByteArrayLiteral("EGL_NV_stream_attrib"), - QByteArrayLiteral("EGL_EXT_stream_acquire_mode"), - QByteArrayLiteral("EGL_KHR_stream_consumer_gltexture"), - QByteArrayLiteral("EGL_WL_wayland_eglstream") - }; - for (const QByteArray &ext : requiredExtensions) { - if (!hasExtension(ext)) { - setFailed(QStringLiteral("Missing required EGL extension: ") + ext); - return false; - } - } - - pEglCreateStreamAttribNV = (PFNEGLCREATESTREAMATTRIBNV)eglGetProcAddress("eglCreateStreamAttribNV"); - pEglGetOutputLayersEXT = (PFNEGLGETOUTPUTLAYERSEXT)eglGetProcAddress("eglGetOutputLayersEXT"); - pEglStreamConsumerOutputEXT = (PFNEGLSTREAMCONSUMEROUTPUTEXT)eglGetProcAddress("eglStreamConsumerOutputEXT"); - pEglCreateStreamProducerSurfaceKHR = (PFNEGLCREATESTREAMPRODUCERSURFACEKHR)eglGetProcAddress("eglCreateStreamProducerSurfaceKHR"); - pEglDestroyStreamKHR = (PFNEGLDESTROYSTREAMKHR)eglGetProcAddress("eglDestroyStreamKHR"); - pEglStreamConsumerAcquireAttribNV = (PFNEGLSTREAMCONSUMERACQUIREATTRIBNV)eglGetProcAddress("eglStreamConsumerAcquireAttribNV"); - pEglStreamConsumerGLTextureExternalKHR = (PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHR)eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR"); - pEglQueryStreamAttribNV = (PFNEGLQUERYSTREAMATTRIBNV)eglGetProcAddress("eglQueryStreamAttribNV"); - pEglStreamConsumerReleaseKHR = (PFNEGLSTREAMCONSUMERRELEASEKHR)eglGetProcAddress("eglStreamConsumerReleaseKHR"); - pEglQueryWaylandBufferWL = (PFNEGLQUERYWAYLANDBUFFERWL)eglGetProcAddress("eglQueryWaylandBufferWL"); - return true; -} - -EglStreamBackend::StreamTexture *EglStreamBackend::lookupStreamTexture(KWaylandServer::SurfaceInterface *surface) -{ - auto it = m_streamTextures.find(surface); - return it != m_streamTextures.end() ? - &it.value() : - nullptr; -} - -void EglStreamBackend::destroyStreamTexture(KWaylandServer::SurfaceInterface *surface) -{ - const StreamTexture &st = m_streamTextures.take(surface); - pEglDestroyStreamKHR(eglDisplay(), st.stream); - glDeleteTextures(1, &st.texture); -} - -void EglStreamBackend::attachStreamConsumer(KWaylandServer::SurfaceInterface *surface, - void *eglStream, - wl_array *attribs) -{ - makeCurrent(); - QVector streamAttribs; - streamAttribs << EGL_WAYLAND_EGLSTREAM_WL << (EGLAttrib)eglStream; - EGLAttrib *attribArray = (EGLAttrib *)attribs->data; - for (unsigned int i = 0; i < attribs->size; ++i) { - streamAttribs << attribArray[i]; - } - streamAttribs << EGL_NONE; - - EGLStreamKHR stream = pEglCreateStreamAttribNV(eglDisplay(), streamAttribs.data()); - if (stream == EGL_NO_STREAM_KHR) { - qCWarning(KWIN_DRM) << "Failed to create EGL stream:" << getEglErrorString(); - return; - } - - GLuint texture; - StreamTexture *st = lookupStreamTexture(surface); - if (st != nullptr) { - pEglDestroyStreamKHR(eglDisplay(), st->stream); - st->stream = stream; - texture = st->texture; - } else { - StreamTexture newSt = { stream, 0 }; - glGenTextures(1, &newSt.texture); - m_streamTextures.insert(surface, newSt); - texture = newSt.texture; - - connect(surface, &KWaylandServer::SurfaceInterface::destroyed, this, - [surface, this]() { - makeCurrent(); - destroyStreamTexture(surface); - }); - } - - glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); - if (!pEglStreamConsumerGLTextureExternalKHR(eglDisplay(), stream)) { - qCWarning(KWIN_DRM) << "Failed to bind EGL stream to texture:" << getEglErrorString(); - } - glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); -} - -void EglStreamBackend::init() -{ - if (!m_gpu->atomicModeSetting()) { - setFailed("EGLStream backend requires atomic modesetting"); - return; - } - - if (isPrimary()) { - if (!initializeEgl()) { - setFailed("Failed to initialize EGL api"); - return; - } - if (!initRenderingContext()) { - setFailed("Failed to initialize rendering context"); - return; - } - - initKWinGL(); - setSupportsBufferAge(false); - initWayland(); - - using namespace KWaylandServer; - m_eglStreamControllerInterface = new EglStreamControllerInterface(waylandServer()->display()); - connect(m_eglStreamControllerInterface, &EglStreamControllerInterface::streamConsumerAttached, this, - &EglStreamBackend::attachStreamConsumer); - } else { - // secondary NVidia GPUs only import dumb buffers - const auto outputs = m_gpu->outputs(); - for (DrmAbstractOutput *drmOutput : outputs) { - addOutput(drmOutput); - } - } -} - -bool EglStreamBackend::initRenderingContext() -{ - initBufferConfigs(); - - if (!createContext()) { - return false; - } - - const auto outputs = m_gpu->outputs(); - for (DrmAbstractOutput *drmOutput : outputs) { - addOutput(drmOutput); - } - return !m_outputs.isEmpty() && makeContextCurrent(m_outputs.first()); -} - -bool EglStreamBackend::resetOutput(Output &o) -{ - const auto &drmOutput = o.output; - QSize sourceSize = drmOutput->sourceSize(); - - if (isPrimary()) { - // dumb buffer used for modesetting - o.buffer = QSharedPointer::create(m_gpu, sourceSize); - o.targetPlane = drmOutput->pipeline()->pending.crtc->primaryPlane(); - - EGLAttrib streamAttribs[] = { - EGL_STREAM_FIFO_LENGTH_KHR, 0, // mailbox mode - EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE, - EGL_NONE - }; - EGLStreamKHR stream = pEglCreateStreamAttribNV(eglDisplay(), streamAttribs); - if (stream == EGL_NO_STREAM_KHR) { - qCCritical(KWIN_DRM) << "Failed to create EGL stream for output:" << getEglErrorString(); - return false; - } - - EGLAttrib outputAttribs[3]; - outputAttribs[0] = EGL_DRM_PLANE_EXT; - outputAttribs[1] = o.targetPlane->id(); - outputAttribs[2] = EGL_NONE; - EGLint numLayers; - EGLOutputLayerEXT outputLayer; - pEglGetOutputLayersEXT(eglDisplay(), outputAttribs, &outputLayer, 1, &numLayers); - if (numLayers == 0) { - qCCritical(KWIN_DRM) << "No EGL output layers found"; - return false; - } - - pEglStreamConsumerOutputEXT(eglDisplay(), stream, outputLayer); - EGLint streamProducerAttribs[] = { - EGL_WIDTH, sourceSize.width(), - EGL_HEIGHT, sourceSize.height(), - EGL_NONE - }; - EGLSurface eglSurface = pEglCreateStreamProducerSurfaceKHR(eglDisplay(), config(), stream, - streamProducerAttribs); - if (eglSurface == EGL_NO_SURFACE) { - qCCritical(KWIN_DRM) << "Failed to create EGL surface for output:" << getEglErrorString(); - return false; - } - - if (o.eglSurface != EGL_NO_SURFACE) { - if (surface() == o.eglSurface) { - setSurface(eglSurface); - } - eglDestroySurface(eglDisplay(), o.eglSurface); - } - - if (o.eglStream != EGL_NO_STREAM_KHR) { - pEglDestroyStreamKHR(eglDisplay(), o.eglStream); - } - - o.eglStream = stream; - o.eglSurface = eglSurface; - - if (drmOutput->needsSoftwareTransformation()) { - makeContextCurrent(o); - o.shadowBuffer = QSharedPointer::create(o.output->pixelSize()); - if (!o.shadowBuffer->isComplete()) { - cleanupOutput(o); - return false; - } - } - } else { - o.dumbSwapchain = QSharedPointer::create(m_gpu, sourceSize); - if (o.dumbSwapchain->isEmpty()) { - return false; - } - } - return true; -} - -bool EglStreamBackend::addOutput(DrmAbstractOutput *output) -{ - Q_ASSERT(output->gpu() == m_gpu); - DrmOutput *drmOutput = qobject_cast(output); - if (drmOutput) { - Output o; - o.output = drmOutput; - if (!resetOutput(o)) { - return false; - } - if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) { - return false; - } - m_outputs.insert(output, o); - return true; - } else { - return false; - } -} - -void EglStreamBackend::removeOutput(DrmAbstractOutput *drmOutput) -{ - Q_ASSERT(drmOutput->gpu() == m_gpu); - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [drmOutput] (const Output &o) { - return o.output == drmOutput; - } - ); - if (it == m_outputs.end()) { - return; - } - cleanupOutput(*it); - m_outputs.erase(it); - if (!isPrimary()) { - renderingBackend()->removeOutput(drmOutput); - } -} - -bool EglStreamBackend::makeContextCurrent(const Output &output) -{ - const EGLSurface surface = output.eglSurface; - if (surface == EGL_NO_SURFACE) { - return false; - } - - if (eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_FALSE) { - qCCritical(KWIN_DRM) << "Failed to make EGL context current:" << getEglErrorString(); - return false; - } - - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - qCWarning(KWIN_DRM) << "Error occurred while making EGL context current:" << getEglErrorString(error); - return false; - } - - const QSize size = output.output->pixelSize(); - glViewport(0, 0, size.width(), size.height()); - return true; -} - -bool EglStreamBackend::initBufferConfigs() -{ - const EGLint configAttribs[] = { - EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 0, - EGL_RENDERABLE_TYPE, isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, - EGL_CONFIG_CAVEAT, EGL_NONE, - EGL_NONE, - }; - EGLint count; - EGLConfig config; - if (!eglChooseConfig(eglDisplay(), configAttribs, &config, 1, &count)) { - qCCritical(KWIN_DRM) << "Failed to query available EGL configs:" << getEglErrorString(); - return false; - } - if (count == 0) { - qCCritical(KWIN_DRM) << "No suitable EGL config found"; - return false; - } - - setConfig(config); - return true; -} - -SurfaceTexture *EglStreamBackend::createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) -{ - return new BasicEGLSurfaceTextureInternal(this, pixmap); -} - -SurfaceTexture *EglStreamBackend::createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) -{ - return new EglStreamSurfaceTextureWayland(this, pixmap); -} - -bool EglStreamBackend::needsReset(const Output &o) const -{ - if (o.targetPlane != o.output->pipeline()->pending.crtc->primaryPlane()) { - return true; - } - QSize surfaceSize = o.dumbSwapchain ? o.dumbSwapchain->size() : o.buffer->size(); - if (surfaceSize != o.output->sourceSize()) { - return true; - } - bool needsTexture = o.output->needsSoftwareTransformation(); - if (needsTexture) { - return !o.shadowBuffer || o.shadowBuffer->textureSize() != o.output->pixelSize(); - } else { - return o.shadowBuffer != nullptr; - } -} - -QRegion EglStreamBackend::beginFrame(AbstractOutput *drmOutput) -{ - Q_ASSERT(m_outputs.contains(drmOutput)); - Output &o = m_outputs[drmOutput]; - if (isPrimary()) { - if (needsReset(o)) { - if (!resetOutput(o)) { - // handle this better? - return {}; - } - } - makeContextCurrent(o); - if (o.shadowBuffer) { - o.shadowBuffer->bind(); - } - return o.output->geometry(); - } else { - return renderingBackend()->beginFrameForSecondaryGpu(o.output); - } -} - -void EglStreamBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) -{ - Q_ASSERT(m_outputs.contains(output)); - Q_UNUSED(renderedRegion); - - Output &renderOutput = m_outputs[output]; - bool frameFailed = false; - - QSharedPointer buffer; - if (isPrimary()) { - buffer = renderOutput.buffer; - if (renderOutput.shadowBuffer) { - renderOutput.shadowBuffer->render(renderOutput.output); - } - if (!eglSwapBuffers(eglDisplay(), renderOutput.eglSurface)) { - qCCritical(KWIN_DRM) << "eglSwapBuffers() failed:" << getEglErrorString(); - frameFailed = true; - } - } else { - if (!renderingBackend()->swapBuffers(static_cast(output), damagedRegion.intersected(output->geometry()))) { - qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << output << "failed!"; - frameFailed = true; - } - buffer = renderOutput.dumbSwapchain->acquireBuffer(); - if (!frameFailed && !renderingBackend()->exportFramebuffer(static_cast(output), buffer->data(), buffer->size(), buffer->stride())) { - qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << output << "failed!"; - frameFailed = true; - } - } - if (!frameFailed && !renderOutput.output->present(buffer, damagedRegion)) { - frameFailed = true; - } - - if (frameFailed) { - RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(output->renderLoop()); - renderLoopPrivate->notifyFrameFailed(); - } else if (isPrimary()) { - EGLAttrib acquireAttribs[] = { - EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)output, - EGL_NONE, - }; - if (!pEglStreamConsumerAcquireAttribNV(eglDisplay(), renderOutput.eglStream, acquireAttribs)) { - qCWarning(KWIN_DRM) << "Failed to acquire output EGL stream frame:" << getEglErrorString(); - } - } -} - -QSharedPointer EglStreamBackend::renderTestFrame(DrmAbstractOutput *drmOutput) -{ - Q_ASSERT(m_outputs.contains(drmOutput)); - auto &output = m_outputs[drmOutput]; - auto buffer = output.dumbSwapchain ? output.dumbSwapchain->currentBuffer() : output.buffer; - auto size = drmOutput->sourceSize(); - if (buffer->size() == size) { - return buffer; - } else { - return QSharedPointer::create(m_gpu, size); - } -} - -bool EglStreamBackend::hasOutput(AbstractOutput *output) const -{ - return m_outputs.contains(output); -} - -uint32_t EglStreamBackend::drmFormat() const -{ - return DRM_FORMAT_XRGB8888; -} - -/************************************************ - * EglTexture - ************************************************/ - -EglStreamSurfaceTextureWayland::EglStreamSurfaceTextureWayland(EglStreamBackend *backend, - SurfacePixmapWayland *pixmap) - : BasicEGLSurfaceTextureWayland(backend, pixmap) - , m_backend(backend) -{ -} - -EglStreamSurfaceTextureWayland::~EglStreamSurfaceTextureWayland() -{ - glDeleteRenderbuffers(1, &m_rbo); - glDeleteFramebuffers(1, &m_fbo); - glDeleteTextures(1, &m_textureId); -} - -bool EglStreamSurfaceTextureWayland::acquireStreamFrame(EGLStreamKHR stream) -{ - EGLAttrib streamState; - if (!pEglQueryStreamAttribNV(m_backend->eglDisplay(), stream, - EGL_STREAM_STATE_KHR, &streamState)) { - qCWarning(KWIN_DRM) << "Failed to query EGL stream state:" << getEglErrorString(); - return false; - } - - if (streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { - if (pEglStreamConsumerAcquireAttribNV(m_backend->eglDisplay(), stream, nullptr)) { - return true; - } else { - qCWarning(KWIN_DRM) << "Failed to acquire EGL stream frame:" << getEglErrorString(); - } - } - - // Re-use previous texture contents if no new frame is available - // or if acquisition fails for some reason - return false; -} - -void EglStreamSurfaceTextureWayland::createFbo() -{ - glDeleteRenderbuffers(1, &m_rbo); - glDeleteFramebuffers(1, &m_fbo); - - GLuint oldReadFbo = 0; - GLuint oldDrawFbo = 0; - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, reinterpret_cast(&oldReadFbo)); - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, reinterpret_cast(&oldDrawFbo)); - - glGenFramebuffers(1, &m_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glGenRenderbuffers(1, &m_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_texture->width(), m_texture->height()); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, oldReadFbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDrawFbo); -} - -// Renders the contents of the given EXTERNAL_OES texture -// to the scratch framebuffer, then copies this to m_texture -void EglStreamSurfaceTextureWayland::copyExternalTexture(GLuint tex) -{ - GLint oldViewport[4], oldProgram, oldReadFbo, oldDrawFbo; - glGetIntegerv(GL_VIEWPORT, oldViewport); - glViewport(0, 0, m_texture->width(), m_texture->height()); - glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgram); - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, reinterpret_cast(&oldReadFbo)); - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, reinterpret_cast(&oldDrawFbo)); - glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); - glEnable(GL_TEXTURE_EXTERNAL_OES); - - GLfloat yTop = texture()->isYInverted() ? 0 : 1; - glBegin(GL_QUADS); - glTexCoord2f(0, yTop); - glVertex2f(-1, 1); - glTexCoord2f(0, 1 - yTop); - glVertex2f(-1, -1); - glTexCoord2f(1, 1 - yTop); - glVertex2f(1, -1); - glTexCoord2f(1, yTop); - glVertex2f(1, 1); - glEnd(); - - texture()->bind(); - glCopyTexImage2D(m_texture->target(), 0, m_format, 0, 0, m_texture->width(), m_texture->height(), 0); - texture()->unbind(); - - glDisable(GL_TEXTURE_EXTERNAL_OES); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, oldReadFbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDrawFbo); - glUseProgram(oldProgram); - glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); -} - -bool EglStreamSurfaceTextureWayland::attachBuffer(KWaylandServer::ClientBuffer *buffer) -{ - GLenum oldFormat = m_format; - m_format = buffer->hasAlphaChannel() ? GL_RGBA : GL_RGB; - - EGLint yInverted, wasYInverted = texture()->isYInverted(); - if (!pEglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_WAYLAND_Y_INVERTED_WL, &yInverted)) { - yInverted = EGL_TRUE; - } - texture()->setYInverted(yInverted); - - return oldFormat != m_format || wasYInverted != texture()->isYInverted(); -} - -bool EglStreamSurfaceTextureWayland::checkBuffer(KWaylandServer::SurfaceInterface *surface, - KWaylandServer::ClientBuffer *buffer) -{ - EGLAttrib attribs[] = { - EGL_WAYLAND_EGLSTREAM_WL, (EGLAttrib)buffer->resource(), - EGL_NONE - }; - EGLStreamKHR stream = pEglCreateStreamAttribNV(m_backend->eglDisplay(), attribs); - if (stream == EGL_NO_STREAM_KHR) { - // eglCreateStreamAttribNV generates EGL_BAD_ACCESS if the - // provided buffer is not a wl_eglstream. In that case, clean up - // the old stream and fall back to the dmabuf or shm attach - // paths. - EGLint err = eglGetError(); - if (err == EGL_BAD_ACCESS) { - m_backend->destroyStreamTexture(surface); - return false; - } - // Otherwise it should have generated EGL_BAD_STREAM_KHR since - // we've already created an EGLStream for it. - Q_ASSERT(err == EGL_BAD_STREAM_KHR); - } else { - // If eglCreateStreamAttribNV *didn't* fail, that means the - // buffer is a wl_eglstream but it hasn't been attached to a - // consumer for some reason. Not much we can do here. - qCCritical(KWIN_DRM) << "Untracked wl_eglstream attached to surface"; - pEglDestroyStreamKHR(m_backend->eglDisplay(), stream); - } - return true; -} - -bool EglStreamSurfaceTextureWayland::create() -{ - using namespace KWaylandServer; - SurfaceInterface *surface = m_pixmap->surface(); - const EglStreamBackend::StreamTexture *st = m_backend->lookupStreamTexture(surface); - if (m_pixmap->buffer() && st != nullptr && checkBuffer(surface, m_pixmap->buffer())) { - - glGenTextures(1, &m_textureId); - m_texture.reset(new GLTexture(m_textureId, 0, m_pixmap->buffer()->size())); - m_texture->setWrapMode(GL_CLAMP_TO_EDGE); - m_texture->setFilter(GL_LINEAR); - - attachBuffer(surface->buffer()); - createFbo(); - - if (acquireStreamFrame(st->stream)) { - copyExternalTexture(st->texture); - if (!pEglStreamConsumerReleaseKHR(m_backend->eglDisplay(), st->stream)) { - qCWarning(KWIN_DRM) << "Failed to release EGL stream:" << getEglErrorString(); - } - } - return true; - } else { - // Not an EGLStream surface - return BasicEGLSurfaceTextureWayland::create(); - } -} - -void EglStreamSurfaceTextureWayland::update(const QRegion ®ion) -{ - using namespace KWaylandServer; - SurfaceInterface *surface = m_pixmap->surface(); - const EglStreamBackend::StreamTexture *st = m_backend->lookupStreamTexture(surface); - if (m_pixmap->buffer() && st != nullptr && checkBuffer(surface, m_pixmap->buffer())) { - - if (attachBuffer(surface->buffer())) { - createFbo(); - } - - if (acquireStreamFrame(st->stream)) { - copyExternalTexture(st->texture); - if (!pEglStreamConsumerReleaseKHR(m_backend->eglDisplay(), st->stream)) { - qCWarning(KWIN_DRM) << "Failed to release EGL stream:" << getEglErrorString(); - } - } - } else { - // Not an EGLStream surface - BasicEGLSurfaceTextureWayland::update(region); - } -} - -} // namespace diff --git a/src/backends/drm/egl_stream_backend.h b/src/backends/drm/egl_stream_backend.h deleted file mode 100644 index d0b8e6272b..0000000000 --- a/src/backends/drm/egl_stream_backend.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2019 NVIDIA Inc. - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#ifndef KWIN_EGL_STREAM_BACKEND_H -#define KWIN_EGL_STREAM_BACKEND_H -#include "abstract_egl_drm_backend.h" -#include "basiceglsurfacetexture_wayland.h" -#include -#include -#include - -namespace KWin -{ - -class DrmAbstractOutput; -class DrmDumbBuffer; -class DumbSwapchain; -class ShadowBuffer; -class DrmCrtc; -class DrmPlane; - -/** - * @brief OpenGL Backend using Egl with an EGLDevice. - */ -class EglStreamBackend : public AbstractEglDrmBackend -{ - Q_OBJECT -public: - EglStreamBackend(DrmBackend *b, DrmGpu *gpu); - ~EglStreamBackend() override; - SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; - SurfaceTexture *createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; - QRegion beginFrame(AbstractOutput *output) override; - void endFrame(AbstractOutput *output, const QRegion &damage, const QRegion &damagedRegion) override; - void init() override; - - bool hasOutput(AbstractOutput *output) const override; - bool addOutput(DrmAbstractOutput *output) override; - void removeOutput(DrmAbstractOutput *output) override; - - QSharedPointer renderTestFrame(DrmAbstractOutput *output) override; - uint32_t drmFormat() const override; - -protected: - void cleanupSurfaces() override; - -private: - bool initializeEgl(); - bool initBufferConfigs(); - bool initRenderingContext(); - struct StreamTexture - { - EGLStreamKHR stream; - GLuint texture; - }; - StreamTexture *lookupStreamTexture(KWaylandServer::SurfaceInterface *surface); - void destroyStreamTexture(KWaylandServer::SurfaceInterface *surface); - void attachStreamConsumer(KWaylandServer::SurfaceInterface *surface, - void *eglStream, - wl_array *attribs); - struct Output - { - DrmOutput *output = nullptr; - QSharedPointer buffer; - EGLSurface eglSurface = EGL_NO_SURFACE; - EGLStreamKHR eglStream = EGL_NO_STREAM_KHR; - QSharedPointer shadowBuffer; - - DrmPlane *targetPlane = nullptr; - - // for operation as secondary GPU - QSharedPointer dumbSwapchain; - }; - bool resetOutput(Output &output); - bool createEglSurface(Output &o); - bool makeContextCurrent(const Output &output); - void cleanupOutput(Output &output); - bool needsReset(const Output &o) const; - - QMap m_outputs; - KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface; - QHash m_streamTextures; - - friend class EglStreamSurfaceTextureWayland; -}; - -class EglStreamSurfaceTextureWayland : public BasicEGLSurfaceTextureWayland -{ -public: - EglStreamSurfaceTextureWayland(EglStreamBackend *backend, SurfacePixmapWayland *pixmap); - ~EglStreamSurfaceTextureWayland() override; - - bool create() override; - void update(const QRegion ®ion) override; - -private: - bool acquireStreamFrame(EGLStreamKHR stream); - void createFbo(); - void copyExternalTexture(GLuint tex); - bool attachBuffer(KWaylandServer::ClientBuffer *buffer); - bool checkBuffer(KWaylandServer::SurfaceInterface *surface, - KWaylandServer::ClientBuffer *buffer); - - EglStreamBackend *m_backend; - GLuint m_fbo, m_rbo, m_textureId; - GLenum m_format; -}; - -} // namespace - -#endif diff --git a/src/config-kwin.h.cmake b/src/config-kwin.h.cmake index e5eae97cf8..8a893a01d2 100644 --- a/src/config-kwin.h.cmake +++ b/src/config-kwin.h.cmake @@ -16,7 +16,6 @@ #cmakedefine01 HAVE_X11_XINPUT #cmakedefine01 HAVE_GBM #cmakedefine01 HAVE_GBM_BO_GET_FD_FOR_PLANE -#cmakedefine01 HAVE_EGL_STREAMS #cmakedefine01 HAVE_WAYLAND_EGL #cmakedefine01 HAVE_SYS_PRCTL_H #cmakedefine01 HAVE_PR_SET_DUMPABLE diff --git a/src/workspace.cpp b/src/workspace.cpp index c75e8120e8..ee42b4585d 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -1512,12 +1512,6 @@ QString Workspace::supportInformation() const support.append(yes); #else support.append(no); -#endif - support.append(QStringLiteral("HAVE_EGL_STREAMS: ")); -#if HAVE_EGL_STREAMS - support.append(yes); -#else - support.append(no); #endif support.append(QStringLiteral("HAVE_X11_XCB: ")); #if HAVE_X11_XCB