From d8e57f78863b76ed5945e7216d6dbe19c9e14cc8 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Wed, 7 Jun 2023 17:07:44 +0200 Subject: [PATCH] backends/drm: improve multi gpu performance with NVidia as secondary GPU With the Nvidia driver, linear textures are external_only, so additional measures need to be taken to make the egl import path work CCBUG: 452219 --- src/backends/drm/drm_egl_backend.cpp | 12 ++++ src/backends/drm/drm_egl_backend.h | 3 + src/backends/drm/drm_egl_layer_surface.cpp | 23 +++++-- src/libkwineffects/kwineglimagetexture.cpp | 15 +++-- src/libkwineffects/kwineglimagetexture.h | 4 +- src/libkwineffects/kwingltexture.cpp | 10 +-- src/libkwineffects/kwingltexture.h | 2 +- src/libkwineffects/kwinglutils.cpp | 31 +++++---- src/libkwineffects/kwinglutils.h | 1 + .../scenes/opengl/CMakeLists.txt | 1 + .../scenes/opengl/eglcontext.cpp | 17 +++-- .../scenes/opengl/eglcontext.h | 2 +- .../scenes/opengl/egldisplay.cpp | 31 +++++++-- .../scenes/opengl/egldisplay.h | 14 +++- .../scenes/opengl/eglnativefence.cpp | 66 +++++++++++++++++++ .../scenes/opengl/eglnativefence.h | 38 +++++++++++ src/plugins/screencast/CMakeLists.txt | 1 - src/plugins/screencast/eglnativefence.cpp | 50 -------------- src/plugins/screencast/eglnativefence.h | 33 ---------- src/plugins/screencast/screencaststream.cpp | 4 +- src/utils/filedescriptor.cpp | 8 +++ src/utils/filedescriptor.h | 1 + 22 files changed, 231 insertions(+), 136 deletions(-) create mode 100644 src/platformsupport/scenes/opengl/eglnativefence.cpp create mode 100644 src/platformsupport/scenes/opengl/eglnativefence.h delete mode 100644 src/plugins/screencast/eglnativefence.cpp delete mode 100644 src/plugins/screencast/eglnativefence.h diff --git a/src/backends/drm/drm_egl_backend.cpp b/src/backends/drm/drm_egl_backend.cpp index fcf6305cea..9e901eec19 100644 --- a/src/backends/drm/drm_egl_backend.cpp +++ b/src/backends/drm/drm_egl_backend.cpp @@ -101,6 +101,18 @@ bool EglGbmBackend::initRenderingContext() return initBufferConfigs(eglDisplayObject()) && createContext(EGL_NO_CONFIG_KHR) && makeCurrent(); } +EglDisplay *EglGbmBackend::displayForGpu(DrmGpu *gpu) +{ + if (gpu == m_backend->primaryGpu()) { + return eglDisplayObject(); + } + auto display = gpu->eglDisplay(); + if (!display) { + display = createEglDisplay(gpu); + } + return display; +} + EglContext *EglGbmBackend::contextForGpu(DrmGpu *gpu) { if (gpu == m_backend->primaryGpu()) { diff --git a/src/backends/drm/drm_egl_backend.h b/src/backends/drm/drm_egl_backend.h index f471272d59..3a9c610e51 100644 --- a/src/backends/drm/drm_egl_backend.h +++ b/src/backends/drm/drm_egl_backend.h @@ -34,6 +34,8 @@ class DrmGpu; class EglGbmLayer; class DrmOutputLayer; class DrmPipeline; +class EglContext; +class EglDisplay; struct GbmFormat { @@ -71,6 +73,7 @@ public: std::optional gbmFormatForDrmFormat(uint32_t format) const; DrmGpu *gpu() const; + EglDisplay *displayForGpu(DrmGpu *gpu); EglContext *contextForGpu(DrmGpu *gpu); private: diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index 63b5d7bef6..0a74a5b8d3 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -15,6 +15,7 @@ #include "drm_gbm_swapchain.h" #include "drm_gpu.h" #include "drm_logging.h" +#include "platformsupport/scenes/opengl/eglnativefence.h" #include #include @@ -278,7 +279,7 @@ std::optional EglGbmLayerSurface::createSurface(con if (!context || context->isSoftwareRenderer()) { return std::nullopt; } - renderModifiers = context->displayObject()->supportedDrmFormats()[format]; + renderModifiers = context->displayObject()->allSupportedDrmFormats()[format]; } Surface ret; ret.importMode = importMode; @@ -357,11 +358,23 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface &surfa { Q_ASSERT(surface.importGbmSwapchain); + EGLNativeFence sourceFence(m_eglBackend->eglDisplay()); + + const auto display = m_eglBackend->displayForGpu(m_gpu); + // the NVidia proprietary driver supports neither implicit sync nor EGL_ANDROID_native_fence_sync + if (!sourceFence.isValid() || !display->supportsNativeFence()) { + glFinish(); + } const auto context = m_eglBackend->contextForGpu(m_gpu); - if (!context || context->isSoftwareRenderer()) { + if (!context || context->isSoftwareRenderer() || !context->makeCurrent()) { return nullptr; } - context->makeCurrent(); + + if (sourceFence.isValid()) { + const auto destinationFence = EGLNativeFence::importFence(context->displayObject()->handle(), sourceFence.fileDescriptor().duplicate()); + destinationFence.waitSync(); + } + auto &sourceTexture = surface.importedTextureCache[sourceBuffer]; if (!sourceTexture) { sourceTexture = context->importDmaBufAsTexture(*sourceBuffer->dmabufAttributes()); @@ -379,10 +392,8 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface &surfa GLFramebuffer *fbo = slot->framebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle()); glViewport(0, 0, fbo->size().width(), fbo->size().height()); - glClearColor(0, 1, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - const auto shader = context->shaderManager()->pushShader(ShaderTrait::MapTexture); + const auto shader = context->shaderManager()->pushShader(sourceTexture->target() == GL_TEXTURE_EXTERNAL_OES ? ShaderTrait::MapExternalTexture : ShaderTrait::MapTexture); QMatrix4x4 mat; mat.scale(1, -1); mat.ortho(QRect(QPoint(), fbo->size())); diff --git a/src/libkwineffects/kwineglimagetexture.cpp b/src/libkwineffects/kwineglimagetexture.cpp index fd5e763162..90d6abfac7 100644 --- a/src/libkwineffects/kwineglimagetexture.cpp +++ b/src/libkwineffects/kwineglimagetexture.cpp @@ -16,8 +16,8 @@ namespace KWin { -EGLImageTexture::EGLImageTexture(::EGLDisplay display, EGLImage image, uint textureId, int internalFormat, const QSize &size) - : GLTexture(textureId, internalFormat, size, 1, true, TextureTransform::MirrorY) +EGLImageTexture::EGLImageTexture(::EGLDisplay display, EGLImage image, uint textureId, int internalFormat, const QSize &size, uint32_t target) + : GLTexture(target, textureId, internalFormat, size, 1, true, TextureTransform::MirrorY) , m_image(image) , m_display(display) { @@ -28,7 +28,7 @@ EGLImageTexture::~EGLImageTexture() eglDestroyImageKHR(m_display, m_image); } -std::shared_ptr EGLImageTexture::create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size) +std::shared_ptr EGLImageTexture::create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size, bool externalOnly) { if (image == EGL_NO_IMAGE) { return nullptr; @@ -38,10 +38,11 @@ std::shared_ptr EGLImageTexture::create(::EGLDisplay display, E if (!texture) { return nullptr; } - glBindTexture(GL_TEXTURE_2D, texture); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); - glBindTexture(GL_TEXTURE_2D, 0); - return std::make_shared(display, image, texture, internalFormat, size); + const uint32_t target = externalOnly ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; + glBindTexture(target, texture); + glEGLImageTargetTexture2DOES(target, image); + glBindTexture(target, 0); + return std::make_shared(display, image, texture, internalFormat, size, target); } } // namespace KWin diff --git a/src/libkwineffects/kwineglimagetexture.h b/src/libkwineffects/kwineglimagetexture.h index c9da5d41d1..d851b04d0c 100644 --- a/src/libkwineffects/kwineglimagetexture.h +++ b/src/libkwineffects/kwineglimagetexture.h @@ -22,10 +22,10 @@ namespace KWin class KWINGLUTILS_EXPORT EGLImageTexture : public GLTexture { public: - explicit EGLImageTexture(::EGLDisplay display, EGLImageKHR image, uint textureId, int internalFormat, const QSize &size); + explicit EGLImageTexture(::EGLDisplay display, EGLImageKHR image, uint textureId, int internalFormat, const QSize &size, uint32_t target); ~EGLImageTexture() override; - static std::shared_ptr create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size); + static std::shared_ptr create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size, bool externalOnly); EGLImageKHR m_image; ::EGLDisplay m_display; diff --git a/src/libkwineffects/kwingltexture.cpp b/src/libkwineffects/kwingltexture.cpp index 3845bc821c..681d2f366d 100644 --- a/src/libkwineffects/kwingltexture.cpp +++ b/src/libkwineffects/kwingltexture.cpp @@ -88,8 +88,8 @@ GLTexture::GLTexture(GLenum target) d->m_target = target; } -GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels, bool owning, TextureTransforms transform) - : GLTexture(GL_TEXTURE_2D) +GLTexture::GLTexture(GLenum target, GLuint textureId, GLenum internalFormat, const QSize &size, int levels, bool owning, TextureTransforms transform) + : GLTexture(target) { d->m_owning = owning; d->m_texture = textureId; @@ -602,7 +602,7 @@ QImage GLTexture::toImage() const std::unique_ptr GLTexture::createNonOwningWrapper(GLuint textureId, GLenum internalFormat, const QSize &size) { - return std::unique_ptr(new GLTexture(textureId, internalFormat, size, 1, false, TextureTransforms{})); + return std::unique_ptr(new GLTexture(GL_TEXTURE_2D, textureId, internalFormat, size, 1, false, TextureTransforms{})); } std::unique_ptr GLTexture::allocate(GLenum internalFormat, const QSize &size, int levels) @@ -635,7 +635,7 @@ std::unique_ptr GLTexture::allocate(GLenum internalFormat, const QSiz // internalFormat() won't need to be specialized for GLES2. } glBindTexture(GL_TEXTURE_2D, 0); - return std::unique_ptr(new GLTexture(texture, internalFormat, size, levels, true, TextureTransforms{})); + return std::unique_ptr(new GLTexture(GL_TEXTURE_2D, texture, internalFormat, size, levels, true, TextureTransforms{})); } std::unique_ptr GLTexture::upload(const QImage &image) @@ -695,7 +695,7 @@ std::unique_ptr GLTexture::upload(const QImage &image) } } glBindTexture(GL_TEXTURE_2D, 0); - return std::unique_ptr(new GLTexture(texture, internalFormat, image.size(), 1, true, TextureTransform::MirrorY)); + return std::unique_ptr(new GLTexture(GL_TEXTURE_2D, texture, internalFormat, image.size(), 1, true, TextureTransform::MirrorY)); } std::unique_ptr GLTexture::upload(const QPixmap &pixmap) diff --git a/src/libkwineffects/kwingltexture.h b/src/libkwineffects/kwingltexture.h index 9570504353..319aae9aaa 100644 --- a/src/libkwineffects/kwingltexture.h +++ b/src/libkwineffects/kwingltexture.h @@ -152,7 +152,7 @@ public: static std::unique_ptr upload(const QPixmap &pixmap); protected: - explicit GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels, bool owning, TextureTransforms transform); + explicit GLTexture(GLenum target, GLuint textureId, GLenum internalFormat, const QSize &size, int levels, bool owning, TextureTransforms transform); const std::unique_ptr d; diff --git a/src/libkwineffects/kwinglutils.cpp b/src/libkwineffects/kwinglutils.cpp index f2bde82cc0..ed1e66aaa3 100644 --- a/src/libkwineffects/kwinglutils.cpp +++ b/src/libkwineffects/kwinglutils.cpp @@ -727,7 +727,7 @@ QByteArray ShaderManager::generateVertexSource(ShaderTraits traits) const } stream << attribute << " vec4 position;\n"; - if (traits & ShaderTrait::MapTexture) { + if (traits & (ShaderTrait::MapTexture | ShaderTrait::MapExternalTexture)) { stream << attribute << " vec4 texcoord;\n\n"; stream << varying << " vec2 texcoord0;\n\n"; } else { @@ -737,7 +737,7 @@ QByteArray ShaderManager::generateVertexSource(ShaderTraits traits) const stream << "uniform mat4 modelViewProjectionMatrix;\n\n"; stream << "void main()\n{\n"; - if (traits & ShaderTrait::MapTexture) { + if (traits & (ShaderTrait::MapTexture | ShaderTrait::MapExternalTexture)) { stream << " texcoord0 = texcoord.st;\n"; } @@ -785,21 +785,21 @@ QByteArray ShaderManager::generateFragmentSource(ShaderTraits traits) const if (traits & ShaderTrait::MapTexture) { stream << "uniform sampler2D sampler;\n"; - - if (traits & ShaderTrait::Modulate) { - stream << "uniform vec4 modulation;\n"; - } - if (traits & ShaderTrait::AdjustSaturation) { - stream << "uniform float saturation;\n"; - stream << "uniform vec3 primaryBrightness;\n"; - } - - stream << "\n" - << varying << " vec2 texcoord0;\n"; - + stream << varying << " vec2 texcoord0;\n"; + } else if (traits & ShaderTrait::MapExternalTexture) { + stream << "#extension GL_OES_EGL_image_external : require\n\n"; + stream << "uniform samplerExternalOES sampler;\n"; + stream << varying << " vec2 texcoord0;\n"; } else if (traits & ShaderTrait::UniformColor) { stream << "uniform vec4 geometryColor;\n"; } + if (traits & ShaderTrait::Modulate) { + stream << "uniform vec4 modulation;\n"; + } + if (traits & ShaderTrait::AdjustSaturation) { + stream << "uniform float saturation;\n"; + stream << "uniform vec3 primaryBrightness;\n"; + } if (traits & ShaderTrait::TransformColorspace) { stream << "const int sRGB_EOTF = 0;\n"; stream << "const int linear_EOTF = 1;\n"; @@ -851,6 +851,9 @@ QByteArray ShaderManager::generateFragmentSource(ShaderTraits traits) const stream << " vec4 result;\n"; if (traits & ShaderTrait::MapTexture) { stream << " result = " << textureLookup << "(sampler, texcoord0);\n"; + } else if (traits & ShaderTrait::MapExternalTexture) { + // external textures require texture2D for sampling + stream << " result = texture2D(sampler, texcoord0);\n"; } else if (traits & ShaderTrait::UniformColor) { stream << " result = geometryColor;\n"; } diff --git a/src/libkwineffects/kwinglutils.h b/src/libkwineffects/kwinglutils.h index 7daaeb2321..d75754718e 100644 --- a/src/libkwineffects/kwinglutils.h +++ b/src/libkwineffects/kwinglutils.h @@ -197,6 +197,7 @@ enum class ShaderTrait { Modulate = (1 << 2), AdjustSaturation = (1 << 3), TransformColorspace = (1 << 4), + MapExternalTexture = (1 << 5), }; Q_DECLARE_FLAGS(ShaderTraits, ShaderTrait) diff --git a/src/platformsupport/scenes/opengl/CMakeLists.txt b/src/platformsupport/scenes/opengl/CMakeLists.txt index 94e0384a56..c6f5b03cd5 100644 --- a/src/platformsupport/scenes/opengl/CMakeLists.txt +++ b/src/platformsupport/scenes/opengl/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(kwin PRIVATE basiceglsurfacetexture_wayland.cpp eglcontext.cpp egldisplay.cpp + eglnativefence.cpp openglbackend.cpp openglsurfacetexture.cpp openglsurfacetexture_internal.cpp diff --git a/src/platformsupport/scenes/opengl/eglcontext.cpp b/src/platformsupport/scenes/opengl/eglcontext.cpp index 5eec5a1e97..114b2765f6 100644 --- a/src/platformsupport/scenes/opengl/eglcontext.cpp +++ b/src/platformsupport/scenes/opengl/eglcontext.cpp @@ -23,10 +23,13 @@ namespace KWin std::unique_ptr EglContext::create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext) { - auto context = createContext(display, config, sharedContext); - if (context) { - eglMakeCurrent(display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, context); - return std::make_unique(display, config, context); + auto handle = createContext(display, config, sharedContext); + if (handle) { + if (!eglMakeCurrent(display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, handle)) { + eglDestroyContext(display->handle(), handle); + return nullptr; + } + return std::make_unique(display, config, handle); } else { return nullptr; } @@ -41,7 +44,6 @@ EglContext::EglContext(EglDisplay *display, EGLConfig config, ::EGLContext conte // It is not legal to not have a vertex array object bound in a core context // to make code handling old and new OpenGL versions easier, bind a dummy vao that's used for everything if (!isOpenglES() && hasOpenglExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { - makeCurrent(); glGenVertexArrays(1, &m_vao); glBindVertexArray(m_vao); } @@ -49,10 +51,11 @@ EglContext::EglContext(EglDisplay *display, EGLConfig config, ::EGLContext conte EglContext::~EglContext() { + makeCurrent(); if (m_vao) { - makeCurrent(); glDeleteVertexArrays(1, &m_vao); } + m_shaderManager.reset(); doneCurrent(); eglDestroyContext(m_display->handle(), m_handle); } @@ -208,7 +211,7 @@ std::shared_ptr EglContext::importDmaBufAsTexture(const DmaBufAttribu { EGLImageKHR image = m_display->importDmaBufAsImage(attributes); if (image != EGL_NO_IMAGE_KHR) { - return EGLImageTexture::create(m_display->handle(), image, glFormatForDrmFormat(attributes.format), QSize(attributes.width, attributes.height)); + return EGLImageTexture::create(m_display->handle(), image, glFormatForDrmFormat(attributes.format), QSize(attributes.width, attributes.height), m_display->isExternalOnly(attributes.format, attributes.modifier)); } else { qCWarning(KWIN_OPENGL) << "Error creating EGLImageKHR: " << getEglErrorString(); return nullptr; diff --git a/src/platformsupport/scenes/opengl/eglcontext.h b/src/platformsupport/scenes/opengl/eglcontext.h index d547ba7266..50b9b36d63 100644 --- a/src/platformsupport/scenes/opengl/eglcontext.h +++ b/src/platformsupport/scenes/opengl/eglcontext.h @@ -47,7 +47,7 @@ private: EglDisplay *const m_display; const ::EGLContext m_handle; const EGLConfig m_config; - const std::unique_ptr m_shaderManager; + std::unique_ptr m_shaderManager; uint32_t m_vao = 0; }; diff --git a/src/platformsupport/scenes/opengl/egldisplay.cpp b/src/platformsupport/scenes/opengl/egldisplay.cpp index 1cb2d4bc90..b01d4c52c4 100644 --- a/src/platformsupport/scenes/opengl/egldisplay.cpp +++ b/src/platformsupport/scenes/opengl/egldisplay.cpp @@ -79,7 +79,9 @@ EglDisplay::EglDisplay(::EGLDisplay display, const QList &extensions , m_owning(owning) , m_supportsBufferAge(extensions.contains(QByteArrayLiteral("EGL_EXT_buffer_age")) && qgetenv("KWIN_USE_BUFFER_AGE") != "0") , m_supportsNativeFence(extensions.contains(QByteArrayLiteral("EGL_ANDROID_native_fence_sync"))) - , m_importFormats(queryImportFormats()) + , m_importFormats(queryImportFormats(Filter::Normal)) + , m_externalOnlyFormats(queryImportFormats(Filter::ExternalOnly)) + , m_allImportFormats(queryImportFormats(Filter::None)) { } @@ -220,7 +222,21 @@ QHash> EglDisplay::supportedDrmFormats() const return m_importFormats; } -QHash> EglDisplay::queryImportFormats() const +QHash> EglDisplay::allSupportedDrmFormats() const +{ + return m_allImportFormats; +} + +bool EglDisplay::isExternalOnly(uint32_t format, uint64_t modifier) const +{ + if (const auto it = m_externalOnlyFormats.find(format); it != m_externalOnlyFormats.end()) { + return it->contains(modifier); + } else { + return false; + } +} + +QHash> EglDisplay::queryImportFormats(Filter filter) const { if (!hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import")) || !hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) { return {}; @@ -256,10 +272,13 @@ QHash> EglDisplay::queryImportFormats() const QVector modifiers(count); QVector externalOnly(count); if (eglQueryDmaBufModifiersEXT(m_handle, format, count, modifiers.data(), externalOnly.data(), &count)) { - for (int i = modifiers.size() - 1; i >= 0; i--) { - if (externalOnly[i]) { - modifiers.remove(i); - externalOnly.remove(i); + if (filter != Filter::None) { + const bool external = filter == Filter::Normal; + for (int i = modifiers.size() - 1; i >= 0; i--) { + if (externalOnly[i] == external) { + modifiers.remove(i); + externalOnly.remove(i); + } } } if (!modifiers.empty()) { diff --git a/src/platformsupport/scenes/opengl/egldisplay.h b/src/platformsupport/scenes/opengl/egldisplay.h index 3ae8d99aa1..fccf47fade 100644 --- a/src/platformsupport/scenes/opengl/egldisplay.h +++ b/src/platformsupport/scenes/opengl/egldisplay.h @@ -36,13 +36,23 @@ public: bool supportsBufferAge() const; bool supportsNativeFence() const; QHash> supportedDrmFormats() const; + /** + * includes external formats + */ + QHash> allSupportedDrmFormats() const; + bool isExternalOnly(uint32_t format, uint64_t modifier) const; EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const; static std::unique_ptr create(::EGLDisplay display, bool owning = true); private: - QHash> queryImportFormats() const; + enum class Filter { + None, + Normal, + ExternalOnly + }; + QHash> queryImportFormats(Filter filter) const; const ::EGLDisplay m_handle; const QList m_extensions; @@ -51,6 +61,8 @@ private: const bool m_supportsBufferAge; const bool m_supportsNativeFence; const QHash> m_importFormats; + const QHash> m_externalOnlyFormats; + const QHash> m_allImportFormats; }; } diff --git a/src/platformsupport/scenes/opengl/eglnativefence.cpp b/src/platformsupport/scenes/opengl/eglnativefence.cpp new file mode 100644 index 0000000000..1ae209bb65 --- /dev/null +++ b/src/platformsupport/scenes/opengl/eglnativefence.cpp @@ -0,0 +1,66 @@ +/* + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "eglnativefence.h" + +#include + +namespace KWin +{ + +#ifndef EGL_ANDROID_native_fence_sync +#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 +#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1 +#endif // EGL_ANDROID_native_fence_sync + +EGLNativeFence::EGLNativeFence(::EGLDisplay display) + : EGLNativeFence(display, eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr)) +{ + if (m_sync != EGL_NO_SYNC_KHR) { + // The native fence will get a valid sync file fd only after a flush. + glFlush(); + m_fileDescriptor = FileDescriptor(eglDupNativeFenceFDANDROID(m_display, m_sync)); + } +} + +EGLNativeFence::EGLNativeFence(::EGLDisplay display, EGLSyncKHR sync) + : m_sync(sync) + , m_display(display) +{ +} + +EGLNativeFence::~EGLNativeFence() +{ + m_fileDescriptor.reset(); + if (m_sync != EGL_NO_SYNC_KHR) { + eglDestroySyncKHR(m_display, m_sync); + } +} + +bool EGLNativeFence::isValid() const +{ + return m_sync != EGL_NO_SYNC_KHR && m_fileDescriptor.isValid(); +} + +const FileDescriptor &EGLNativeFence::fileDescriptor() const +{ + return m_fileDescriptor; +} + +bool EGLNativeFence::waitSync() const +{ + return eglWaitSync(m_display, m_sync, 0) == EGL_TRUE; +} + +EGLNativeFence EGLNativeFence::importFence(::EGLDisplay display, FileDescriptor &&fd) +{ + EGLint attributes[] = { + EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd.take(), + EGL_NONE}; + return EGLNativeFence(display, eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, attributes)); +} + +} // namespace KWin diff --git a/src/platformsupport/scenes/opengl/eglnativefence.h b/src/platformsupport/scenes/opengl/eglnativefence.h new file mode 100644 index 0000000000..4eac3d098d --- /dev/null +++ b/src/platformsupport/scenes/opengl/eglnativefence.h @@ -0,0 +1,38 @@ +/* + SPDX-FileCopyrightText: 2020 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +#include "kwin_export.h" +#include "utils/filedescriptor.h" + +namespace KWin +{ + +class KWIN_EXPORT EGLNativeFence +{ +public: + explicit EGLNativeFence(::EGLDisplay display); + explicit EGLNativeFence(::EGLDisplay display, EGLSyncKHR sync); + EGLNativeFence(EGLNativeFence &&) = delete; + EGLNativeFence(const EGLNativeFence &) = delete; + ~EGLNativeFence(); + + bool isValid() const; + const FileDescriptor &fileDescriptor() const; + bool waitSync() const; + + static EGLNativeFence importFence(::EGLDisplay display, FileDescriptor &&fd); + +private: + EGLSyncKHR m_sync = EGL_NO_SYNC_KHR; + ::EGLDisplay m_display = EGL_NO_DISPLAY; + FileDescriptor m_fileDescriptor; +}; + +} // namespace KWin diff --git a/src/plugins/screencast/CMakeLists.txt b/src/plugins/screencast/CMakeLists.txt index 36bb996f3d..6c1e9f1677 100644 --- a/src/plugins/screencast/CMakeLists.txt +++ b/src/plugins/screencast/CMakeLists.txt @@ -1,6 +1,5 @@ kcoreaddons_add_plugin(screencast INSTALL_NAMESPACE "kwin/plugins") target_sources(screencast PRIVATE - eglnativefence.cpp main.cpp outputscreencastsource.cpp pipewirecore.cpp diff --git a/src/plugins/screencast/eglnativefence.cpp b/src/plugins/screencast/eglnativefence.cpp deleted file mode 100644 index 058e1a86c1..0000000000 --- a/src/plugins/screencast/eglnativefence.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - SPDX-FileCopyrightText: 2020 Vlad Zahorodnii - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "eglnativefence.h" - -#include - -namespace KWin -{ - -#ifndef EGL_ANDROID_native_fence_sync -#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 -#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1 -#endif // EGL_ANDROID_native_fence_sync - -EGLNativeFence::EGLNativeFence(::EGLDisplay display) - : m_display(display) -{ - m_sync = eglCreateSyncKHR(m_display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); - if (m_sync != EGL_NO_SYNC_KHR) { - // The native fence will get a valid sync file fd only after a flush. - glFlush(); - m_fileDescriptor = eglDupNativeFenceFDANDROID(m_display, m_sync); - } -} - -EGLNativeFence::~EGLNativeFence() -{ - if (m_fileDescriptor != EGL_NO_NATIVE_FENCE_FD_ANDROID) { - close(m_fileDescriptor); - } - if (m_sync != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(m_display, m_sync); - } -} - -bool EGLNativeFence::isValid() const -{ - return m_sync != EGL_NO_SYNC_KHR && m_fileDescriptor != EGL_NO_NATIVE_FENCE_FD_ANDROID; -} - -int EGLNativeFence::fileDescriptor() const -{ - return m_fileDescriptor; -} - -} // namespace KWin diff --git a/src/plugins/screencast/eglnativefence.h b/src/plugins/screencast/eglnativefence.h deleted file mode 100644 index b570ef7d63..0000000000 --- a/src/plugins/screencast/eglnativefence.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - SPDX-FileCopyrightText: 2020 Vlad Zahorodnii - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#pragma once - -#include - -#include - -namespace KWin -{ - -class EGLNativeFence -{ -public: - explicit EGLNativeFence(::EGLDisplay display); - ~EGLNativeFence(); - - bool isValid() const; - int fileDescriptor() const; - -private: - EGLSyncKHR m_sync = EGL_NO_SYNC_KHR; - ::EGLDisplay m_display = EGL_NO_DISPLAY; - int m_fileDescriptor = -1; - - Q_DISABLE_COPY(EGLNativeFence) -}; - -} // namespace KWin diff --git a/src/plugins/screencast/screencaststream.cpp b/src/plugins/screencast/screencaststream.cpp index 89722955ee..41d559d0df 100644 --- a/src/plugins/screencast/screencaststream.cpp +++ b/src/plugins/screencast/screencaststream.cpp @@ -11,7 +11,6 @@ #include "core/renderbackend.h" #include "cursor.h" #include "dmabuftexture.h" -#include "eglnativefence.h" #include "kwinscreencast_logging.h" #include "libkwineffects/kwineffects.h" #include "libkwineffects/kwinglplatform.h" @@ -19,6 +18,7 @@ #include "libkwineffects/kwinglutils.h" #include "main.h" #include "pipewirecore.h" +#include "platformsupport/scenes/opengl/eglnativefence.h" #include "platformsupport/scenes/opengl/openglbackend.h" #include "scene/workspacescene.h" #include "screencastsource.h" @@ -698,7 +698,7 @@ void ScreenCastStream::tryEnqueue(pw_buffer *buffer) glFinish(); enqueue(); } else { - m_pendingNotifier = std::make_unique(m_pendingFence->fileDescriptor(), QSocketNotifier::Read); + m_pendingNotifier = std::make_unique(m_pendingFence->fileDescriptor().get(), QSocketNotifier::Read); connect(m_pendingNotifier.get(), &QSocketNotifier::activated, this, &ScreenCastStream::enqueue); } } else { diff --git a/src/utils/filedescriptor.cpp b/src/utils/filedescriptor.cpp index 820c2663dd..768f1a22d1 100644 --- a/src/utils/filedescriptor.cpp +++ b/src/utils/filedescriptor.cpp @@ -56,6 +56,14 @@ int FileDescriptor::take() return std::exchange(m_fd, -1); } +void FileDescriptor::reset() +{ + if (m_fd != -1) { + ::close(m_fd); + m_fd = -1; + } +} + FileDescriptor FileDescriptor::duplicate() const { if (m_fd != -1) { diff --git a/src/utils/filedescriptor.h b/src/utils/filedescriptor.h index 1b0647c7ea..b7e694a8ec 100644 --- a/src/utils/filedescriptor.h +++ b/src/utils/filedescriptor.h @@ -25,6 +25,7 @@ public: bool isValid() const; int get() const; int take(); + void reset(); FileDescriptor duplicate() const; private: