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
This commit is contained in:
Xaver Hugl 2023-06-07 17:07:44 +02:00
parent 24bfca7959
commit d8e57f7886
22 changed files with 231 additions and 136 deletions

View file

@ -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()) {

View file

@ -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<GbmFormat> gbmFormatForDrmFormat(uint32_t format) const;
DrmGpu *gpu() const;
EglDisplay *displayForGpu(DrmGpu *gpu);
EglContext *contextForGpu(DrmGpu *gpu);
private:

View file

@ -15,6 +15,7 @@
#include "drm_gbm_swapchain.h"
#include "drm_gpu.h"
#include "drm_logging.h"
#include "platformsupport/scenes/opengl/eglnativefence.h"
#include <drm_fourcc.h>
#include <errno.h>
@ -278,7 +279,7 @@ std::optional<EglGbmLayerSurface::Surface> 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<DrmFramebuffer> 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<DrmFramebuffer> 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()));

View file

@ -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> EGLImageTexture::create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size)
std::shared_ptr<EGLImageTexture> 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> 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<EGLImageTexture>(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<EGLImageTexture>(display, image, texture, internalFormat, size, target);
}
} // namespace KWin

View file

@ -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<EGLImageTexture> create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size);
static std::shared_ptr<EGLImageTexture> create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size, bool externalOnly);
EGLImageKHR m_image;
::EGLDisplay m_display;

View file

@ -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> GLTexture::createNonOwningWrapper(GLuint textureId, GLenum internalFormat, const QSize &size)
{
return std::unique_ptr<GLTexture>(new GLTexture(textureId, internalFormat, size, 1, false, TextureTransforms{}));
return std::unique_ptr<GLTexture>(new GLTexture(GL_TEXTURE_2D, textureId, internalFormat, size, 1, false, TextureTransforms{}));
}
std::unique_ptr<GLTexture> GLTexture::allocate(GLenum internalFormat, const QSize &size, int levels)
@ -635,7 +635,7 @@ std::unique_ptr<GLTexture> GLTexture::allocate(GLenum internalFormat, const QSiz
// internalFormat() won't need to be specialized for GLES2.
}
glBindTexture(GL_TEXTURE_2D, 0);
return std::unique_ptr<GLTexture>(new GLTexture(texture, internalFormat, size, levels, true, TextureTransforms{}));
return std::unique_ptr<GLTexture>(new GLTexture(GL_TEXTURE_2D, texture, internalFormat, size, levels, true, TextureTransforms{}));
}
std::unique_ptr<GLTexture> GLTexture::upload(const QImage &image)
@ -695,7 +695,7 @@ std::unique_ptr<GLTexture> GLTexture::upload(const QImage &image)
}
}
glBindTexture(GL_TEXTURE_2D, 0);
return std::unique_ptr<GLTexture>(new GLTexture(texture, internalFormat, image.size(), 1, true, TextureTransform::MirrorY));
return std::unique_ptr<GLTexture>(new GLTexture(GL_TEXTURE_2D, texture, internalFormat, image.size(), 1, true, TextureTransform::MirrorY));
}
std::unique_ptr<GLTexture> GLTexture::upload(const QPixmap &pixmap)

View file

@ -152,7 +152,7 @@ public:
static std::unique_ptr<GLTexture> 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<GLTexturePrivate> d;

View file

@ -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";
}

View file

@ -197,6 +197,7 @@ enum class ShaderTrait {
Modulate = (1 << 2),
AdjustSaturation = (1 << 3),
TransformColorspace = (1 << 4),
MapExternalTexture = (1 << 5),
};
Q_DECLARE_FLAGS(ShaderTraits, ShaderTrait)

View file

@ -4,6 +4,7 @@ target_sources(kwin PRIVATE
basiceglsurfacetexture_wayland.cpp
eglcontext.cpp
egldisplay.cpp
eglnativefence.cpp
openglbackend.cpp
openglsurfacetexture.cpp
openglsurfacetexture_internal.cpp

View file

@ -23,10 +23,13 @@ namespace KWin
std::unique_ptr<EglContext> 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<EglContext>(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<EglContext>(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<GLTexture> 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;

View file

@ -47,7 +47,7 @@ private:
EglDisplay *const m_display;
const ::EGLContext m_handle;
const EGLConfig m_config;
const std::unique_ptr<ShaderManager> m_shaderManager;
std::unique_ptr<ShaderManager> m_shaderManager;
uint32_t m_vao = 0;
};

View file

@ -79,7 +79,9 @@ EglDisplay::EglDisplay(::EGLDisplay display, const QList<QByteArray> &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<uint32_t, QList<uint64_t>> EglDisplay::supportedDrmFormats() const
return m_importFormats;
}
QHash<uint32_t, QList<uint64_t>> EglDisplay::queryImportFormats() const
QHash<uint32_t, QList<uint64_t>> 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<uint32_t, QList<uint64_t>> 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<uint32_t, QList<uint64_t>> EglDisplay::queryImportFormats() const
QVector<uint64_t> modifiers(count);
QVector<EGLBoolean> 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()) {

View file

@ -36,13 +36,23 @@ public:
bool supportsBufferAge() const;
bool supportsNativeFence() const;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const;
/**
* includes external formats
*/
QHash<uint32_t, QList<uint64_t>> allSupportedDrmFormats() const;
bool isExternalOnly(uint32_t format, uint64_t modifier) const;
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const;
static std::unique_ptr<EglDisplay> create(::EGLDisplay display, bool owning = true);
private:
QHash<uint32_t, QList<uint64_t>> queryImportFormats() const;
enum class Filter {
None,
Normal,
ExternalOnly
};
QHash<uint32_t, QList<uint64_t>> queryImportFormats(Filter filter) const;
const ::EGLDisplay m_handle;
const QList<QByteArray> m_extensions;
@ -51,6 +61,8 @@ private:
const bool m_supportsBufferAge;
const bool m_supportsNativeFence;
const QHash<uint32_t, QList<uint64_t>> m_importFormats;
const QHash<uint32_t, QList<uint64_t>> m_externalOnlyFormats;
const QHash<uint32_t, QList<uint64_t>> m_allImportFormats;
};
}

View file

@ -0,0 +1,66 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "eglnativefence.h"
#include <unistd.h>
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

View file

@ -0,0 +1,38 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <epoxy/egl.h>
#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

View file

@ -1,6 +1,5 @@
kcoreaddons_add_plugin(screencast INSTALL_NAMESPACE "kwin/plugins")
target_sources(screencast PRIVATE
eglnativefence.cpp
main.cpp
outputscreencastsource.cpp
pipewirecore.cpp

View file

@ -1,50 +0,0 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "eglnativefence.h"
#include <unistd.h>
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

View file

@ -1,33 +0,0 @@
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QtGlobal>
#include <epoxy/egl.h>
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

View file

@ -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<QSocketNotifier>(m_pendingFence->fileDescriptor(), QSocketNotifier::Read);
m_pendingNotifier = std::make_unique<QSocketNotifier>(m_pendingFence->fileDescriptor().get(), QSocketNotifier::Read);
connect(m_pendingNotifier.get(), &QSocketNotifier::activated, this, &ScreenCastStream::enqueue);
}
} else {

View file

@ -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) {

View file

@ -25,6 +25,7 @@ public:
bool isValid() const;
int get() const;
int take();
void reset();
FileDescriptor duplicate() const;
private: