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:
parent
24bfca7959
commit
d8e57f7886
22 changed files with 231 additions and 136 deletions
|
@ -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()) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@ enum class ShaderTrait {
|
|||
Modulate = (1 << 2),
|
||||
AdjustSaturation = (1 << 3),
|
||||
TransformColorspace = (1 << 4),
|
||||
MapExternalTexture = (1 << 5),
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(ShaderTraits, ShaderTrait)
|
||||
|
|
|
@ -4,6 +4,7 @@ target_sources(kwin PRIVATE
|
|||
basiceglsurfacetexture_wayland.cpp
|
||||
eglcontext.cpp
|
||||
egldisplay.cpp
|
||||
eglnativefence.cpp
|
||||
openglbackend.cpp
|
||||
openglsurfacetexture.cpp
|
||||
openglsurfacetexture_internal.cpp
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
66
src/platformsupport/scenes/opengl/eglnativefence.cpp
Normal file
66
src/platformsupport/scenes/opengl/eglnativefence.cpp
Normal 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
|
38
src/platformsupport/scenes/opengl/eglnativefence.h
Normal file
38
src/platformsupport/scenes/opengl/eglnativefence.h
Normal 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
|
|
@ -1,6 +1,5 @@
|
|||
kcoreaddons_add_plugin(screencast INSTALL_NAMESPACE "kwin/plugins")
|
||||
target_sources(screencast PRIVATE
|
||||
eglnativefence.cpp
|
||||
main.cpp
|
||||
outputscreencastsource.cpp
|
||||
pipewirecore.cpp
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
bool isValid() const;
|
||||
int get() const;
|
||||
int take();
|
||||
void reset();
|
||||
FileDescriptor duplicate() const;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue