screencast: Address minor issues

icc-effect-master
Vlad Zahorodnii 2020-07-28 16:37:04 +03:00 committed by Vlad Zahorodnii
parent 76b9fb15ea
commit 2103b999e7
9 changed files with 113 additions and 88 deletions

View File

@ -759,11 +759,11 @@ set(kwin_WAYLAND_SRCS
) )
ecm_qt_declare_logging_category(kwin_WAYLAND_SRCS ecm_qt_declare_logging_category(kwin_WAYLAND_SRCS
HEADER HEADER
kwinpipewire_logging.h kwinscreencast_logging.h
IDENTIFIER IDENTIFIER
KWIN_PIPEWIRE KWIN_SCREENCAST
CATEGORY_NAME CATEGORY_NAME
kwin_pipewire kwin_screencast
DEFAULT_SEVERITY DEFAULT_SEVERITY
Warning Warning
) )

View File

@ -21,3 +21,4 @@ kwin_qpa_plugin KWin QtPlatformAbstraction plugin DEFAULT_SEVERITY [CRITICAL] ID
kwin_scene_xrender KWin XRender based compositor scene plugin DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_XRENDER] kwin_scene_xrender KWin XRender based compositor scene plugin DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_XRENDER]
kwin_scene_qpainter KWin QPainter based compositor scene plugin DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_QPAINTER] kwin_scene_qpainter KWin QPainter based compositor scene plugin DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_QPAINTER]
kwin_scene_opengl KWin OpenGL based compositor scene plugins DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_OPENGL] kwin_scene_opengl KWin OpenGL based compositor scene plugins DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_OPENGL]
kwin_screencast KWin Screen Cast Service DEFAULT_SEVERITY [WARNING] IDENTIFIER [KWIN_SCREENCAST]

View File

@ -49,8 +49,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "decorations/decoratedclient.h" #include "decorations/decoratedclient.h"
#include <logging.h> #include <logging.h>
#include "abstract_wayland_output.h"
#include "abstract_egl_backend.h"
#include <KWaylandServer/buffer_interface.h> #include <KWaylandServer/buffer_interface.h>
#include <KWaylandServer/subcompositor_interface.h> #include <KWaylandServer/subcompositor_interface.h>
#include <KWaylandServer/surface_interface.h> #include <KWaylandServer/surface_interface.h>

View File

@ -21,10 +21,15 @@
*/ */
#include "pipewirecore.h" #include "pipewirecore.h"
#include "kwinscreencast_logging.h"
#include <KLocalizedString>
#include <QDebug> #include <QDebug>
#include <QSocketNotifier> #include <QSocketNotifier>
#include <KLocalizedString>
#include "kwinpipewire_logging.h" namespace KWin
{
PipeWireCore::PipeWireCore() PipeWireCore::PipeWireCore()
{ {
@ -56,7 +61,7 @@ void PipeWireCore::onCoreError(void* data, uint32_t id, int seq, int res, const
{ {
Q_UNUSED(seq) Q_UNUSED(seq)
qCWarning(KWIN_PIPEWIRE) << "PipeWire remote error: " << message; qCWarning(KWIN_SCREENCAST) << "PipeWire remote error: " << message;
if (id == PW_ID_CORE && res == -EPIPE) { if (id == PW_ID_CORE && res == -EPIPE) {
PipeWireCore *pw = static_cast<PipeWireCore*>(data); PipeWireCore *pw = static_cast<PipeWireCore*>(data);
Q_EMIT pw->pipewireFailed(QString::fromUtf8(message)); Q_EMIT pw->pipewireFailed(QString::fromUtf8(message));
@ -72,26 +77,26 @@ bool PipeWireCore::init()
connect(notifier, &QSocketNotifier::activated, this, [this] { connect(notifier, &QSocketNotifier::activated, this, [this] {
int result = pw_loop_iterate (pwMainLoop, 0); int result = pw_loop_iterate (pwMainLoop, 0);
if (result < 0) if (result < 0)
qCWarning(KWIN_PIPEWIRE) << "pipewire_loop_iterate failed: " << result; qCWarning(KWIN_SCREENCAST) << "pipewire_loop_iterate failed: " << result;
} }
); );
pwContext = pw_context_new(pwMainLoop, nullptr, 0); pwContext = pw_context_new(pwMainLoop, nullptr, 0);
if (!pwContext) { if (!pwContext) {
qCWarning(KWIN_PIPEWIRE) << "Failed to create PipeWire context"; qCWarning(KWIN_SCREENCAST) << "Failed to create PipeWire context";
m_error = i18n("Failed to create PipeWire context"); m_error = i18n("Failed to create PipeWire context");
return false; return false;
} }
pwCore = pw_context_connect(pwContext, nullptr, 0); pwCore = pw_context_connect(pwContext, nullptr, 0);
if (!pwCore) { if (!pwCore) {
qCWarning(KWIN_PIPEWIRE) << "Failed to connect PipeWire context"; qCWarning(KWIN_SCREENCAST) << "Failed to connect PipeWire context";
m_error = i18n("Failed to connect PipeWire context"); m_error = i18n("Failed to connect PipeWire context");
return false; return false;
} }
if (pw_loop_iterate(pwMainLoop, 0) < 0) { if (pw_loop_iterate(pwMainLoop, 0) < 0) {
qCWarning(KWIN_PIPEWIRE) << "Failed to start main PipeWire loop"; qCWarning(KWIN_SCREENCAST) << "Failed to start main PipeWire loop";
m_error = i18n("Failed to start main PipeWire loop"); m_error = i18n("Failed to start main PipeWire loop");
return false; return false;
} }
@ -113,3 +118,5 @@ QSharedPointer< PipeWireCore > PipeWireCore::self()
} }
return ret; return ret;
} }
} // namespace KWin

View File

@ -22,10 +22,14 @@
#pragma once #pragma once
#include <QObject>
#include <QDebug> #include <QDebug>
#include <spa/utils/hook.h> #include <QObject>
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include <spa/utils/hook.h>
namespace KWin
{
class PipeWireCore : public QObject class PipeWireCore : public QObject
{ {
@ -52,3 +56,5 @@ public:
Q_SIGNALS: Q_SIGNALS:
void pipewireFailed(const QString &message); void pipewireFailed(const QString &message);
}; };
} // namespace KWin

View File

@ -21,36 +21,39 @@
*/ */
#include "pipewirestream.h" #include "pipewirestream.h"
#include "cursor.h"
#include "dmabuftexture.h"
#include "kwineglimagetexture.h"
#include "kwinscreencast_logging.h"
#include "main.h"
#include "pipewirecore.h"
#include "platform.h"
#include "platformsupport/scenes/opengl/drm_fourcc.h"
#include "scenes/opengl/egl_dmabuf.h"
#include "utils.h"
#include <sys/mman.h> #include <KLocalizedString>
#include <fcntl.h>
#include <unistd.h>
#include <gbm.h>
#include <spa/buffer/meta.h>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QPainter> #include <QPainter>
#include "utils.h"
#include "cursor.h"
#include "main.h"
#include "platform.h"
#include "scenes/opengl/egl_dmabuf.h"
#include "platformsupport/scenes/opengl/drm_fourcc.h"
#include "kwineglimagetexture.h"
#include "dmabuftexture.h"
#include "pipewirecore.h"
#include "kwinpipewire_logging.h"
#include <KLocalizedString> #include <spa/buffer/meta.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
namespace KWin
{
void PipeWireStream::onStreamStateChanged(void *data, pw_stream_state old, pw_stream_state state, const char *error_message) void PipeWireStream::onStreamStateChanged(void *data, pw_stream_state old, pw_stream_state state, const char *error_message)
{ {
PipeWireStream *pw = static_cast<PipeWireStream*>(data); PipeWireStream *pw = static_cast<PipeWireStream*>(data);
qCDebug(KWIN_PIPEWIRE) << "state changed"<< pw_stream_state_as_string(old) << " -> " << pw_stream_state_as_string(state) << error_message; qCDebug(KWIN_SCREENCAST) << "state changed"<< pw_stream_state_as_string(old) << " -> " << pw_stream_state_as_string(state) << error_message;
switch (state) { switch (state) {
case PW_STREAM_STATE_ERROR: case PW_STREAM_STATE_ERROR:
qCWarning(KWIN_PIPEWIRE) << "Stream error: " << error_message; qCWarning(KWIN_SCREENCAST) << "Stream error: " << error_message;
break; break;
case PW_STREAM_STATE_PAUSED: case PW_STREAM_STATE_PAUSED:
if (pw->nodeId() == 0 && pw->pwStream) { if (pw->nodeId() == 0 && pw->pwStream) {
@ -84,7 +87,7 @@ void PipeWireStream::newStreamParams()
spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT (paramsBuffer, sizeof (paramsBuffer)); spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT (paramsBuffer, sizeof (paramsBuffer));
spa_rectangle resolution = SPA_RECTANGLE(uint32_t(m_resolution.width()), uint32_t(m_resolution.height())); spa_rectangle resolution = SPA_RECTANGLE(uint32_t(m_resolution.width()), uint32_t(m_resolution.height()));
const auto cursorSize = KWin::Cursors::self()->currentCursor()->themeSize(); const auto cursorSize = Cursors::self()->currentCursor()->themeSize();
const spa_pod *params[] = { const spa_pod *params[] = {
(spa_pod*) spa_pod_builder_add_object(&pod_builder, (spa_pod*) spa_pod_builder_add_object(&pod_builder,
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
@ -110,7 +113,7 @@ void PipeWireStream::onStreamParamChanged(void *data, uint32_t id, const struct
PipeWireStream *pw = static_cast<PipeWireStream *>(data); PipeWireStream *pw = static_cast<PipeWireStream *>(data);
spa_format_video_raw_parse (format, &pw->videoFormat); spa_format_video_raw_parse (format, &pw->videoFormat);
qCDebug(KWIN_PIPEWIRE) << "Stream format changed" << pw << pw->videoFormat.format; qCDebug(KWIN_SCREENCAST) << "Stream format changed" << pw << pw->videoFormat.format;
pw->newStreamParams(); pw->newStreamParams();
} }
@ -122,11 +125,11 @@ void PipeWireStream::onStreamAddBuffer(void *data, pw_buffer *buffer)
spa_data->mapoffset = 0; spa_data->mapoffset = 0;
spa_data->flags = SPA_DATA_FLAG_READWRITE; spa_data->flags = SPA_DATA_FLAG_READWRITE;
QSharedPointer<KWin::DmaBufTexture> dmabuf (KWin::kwinApp()->platform()->createDmaBufTexture(stream->m_resolution)); QSharedPointer<DmaBufTexture> dmabuf(kwinApp()->platform()->createDmaBufTexture(stream->m_resolution));
if (dmabuf) { if (dmabuf) {
spa_data->type = SPA_DATA_DmaBuf; spa_data->type = SPA_DATA_DmaBuf;
spa_data->fd = dmabuf->fd(); spa_data->fd = dmabuf->fd();
spa_data->data = NULL; spa_data->data = nullptr;
spa_data->maxsize = dmabuf->stride() * stream->m_resolution.height(); spa_data->maxsize = dmabuf->stride() * stream->m_resolution.height();
stream->m_dmabufDataForPwBuffer.insert(buffer, dmabuf); stream->m_dmabufDataForPwBuffer.insert(buffer, dmabuf);
@ -138,30 +141,30 @@ void PipeWireStream::onStreamAddBuffer(void *data, pw_buffer *buffer)
spa_data->type = SPA_DATA_MemFd; spa_data->type = SPA_DATA_MemFd;
spa_data->fd = memfd_create("kwin-screencast-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); spa_data->fd = memfd_create("kwin-screencast-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (spa_data->fd == -1) { if (spa_data->fd == -1) {
qCCritical(KWIN_PIPEWIRE) << "memfd: Can't create memfd"; qCCritical(KWIN_SCREENCAST) << "memfd: Can't create memfd";
return; return;
} }
spa_data->mapoffset = 0; spa_data->mapoffset = 0;
if (ftruncate (spa_data->fd, spa_data->maxsize) < 0) { if (ftruncate (spa_data->fd, spa_data->maxsize) < 0) {
qCCritical(KWIN_PIPEWIRE) << "memfd: Can't truncate to" << spa_data->maxsize; qCCritical(KWIN_SCREENCAST) << "memfd: Can't truncate to" << spa_data->maxsize;
return; return;
} }
unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
if (fcntl(spa_data->fd, F_ADD_SEALS, seals) == -1) if (fcntl(spa_data->fd, F_ADD_SEALS, seals) == -1)
qCWarning(KWIN_PIPEWIRE) << "memfd: Failed to add seals"; qCWarning(KWIN_SCREENCAST) << "memfd: Failed to add seals";
spa_data->data = mmap(NULL, spa_data->data = mmap(nullptr,
spa_data->maxsize, spa_data->maxsize,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_SHARED, MAP_SHARED,
spa_data->fd, spa_data->fd,
spa_data->mapoffset); spa_data->mapoffset);
if (spa_data->data == MAP_FAILED) if (spa_data->data == MAP_FAILED)
qCCritical(KWIN_PIPEWIRE) << "memfd: Failed to mmap memory"; qCCritical(KWIN_SCREENCAST) << "memfd: Failed to mmap memory";
else else
qCDebug(KWIN_PIPEWIRE) << "memfd: created successfully" << spa_data->data << spa_data->maxsize; qCDebug(KWIN_SCREENCAST) << "memfd: created successfully" << spa_data->data << spa_data->maxsize;
#endif #endif
} }
} }
@ -212,7 +215,7 @@ bool PipeWireStream::init()
connect(pwCore.data(), &PipeWireCore::pipewireFailed, this, &PipeWireStream::coreFailed); connect(pwCore.data(), &PipeWireCore::pipewireFailed, this, &PipeWireStream::coreFailed);
if (!createStream()) { if (!createStream()) {
qCWarning(KWIN_PIPEWIRE) << "Failed to create PipeWire stream"; qCWarning(KWIN_SCREENCAST) << "Failed to create PipeWire stream";
m_error = i18n("Failed to create PipeWire stream"); m_error = i18n("Failed to create PipeWire stream");
return false; return false;
} }
@ -247,7 +250,7 @@ bool PipeWireStream::createStream()
spa_rectangle resolution = SPA_RECTANGLE(uint32_t(m_resolution.width()), uint32_t(m_resolution.height())); spa_rectangle resolution = SPA_RECTANGLE(uint32_t(m_resolution.width()), uint32_t(m_resolution.height()));
const auto format = m_hasAlpha || m_gbmDevice ? SPA_VIDEO_FORMAT_BGRA : SPA_VIDEO_FORMAT_BGR; const auto format = m_hasAlpha ? SPA_VIDEO_FORMAT_BGRA : SPA_VIDEO_FORMAT_BGR;
const spa_pod *param = (spa_pod*)spa_pod_builder_add_object(&podBuilder, const spa_pod *param = (spa_pod*)spa_pod_builder_add_object(&podBuilder,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
@ -262,16 +265,16 @@ bool PipeWireStream::createStream()
auto flags = pw_stream_flags(PW_STREAM_FLAG_DRIVER | PW_STREAM_FLAG_ALLOC_BUFFERS); auto flags = pw_stream_flags(PW_STREAM_FLAG_DRIVER | PW_STREAM_FLAG_ALLOC_BUFFERS);
if (pw_stream_connect(pwStream, PW_DIRECTION_OUTPUT, SPA_ID_INVALID, flags, &param, 1) != 0) { if (pw_stream_connect(pwStream, PW_DIRECTION_OUTPUT, SPA_ID_INVALID, flags, &param, 1) != 0) {
qCWarning(KWIN_PIPEWIRE) << "Could not connect to stream"; qCWarning(KWIN_SCREENCAST) << "Could not connect to stream";
pw_stream_destroy(pwStream); pw_stream_destroy(pwStream);
return false; return false;
} }
if (m_cursor.mode == KWaylandServer::ScreencastInterface::Embedded) { if (m_cursor.mode == KWaylandServer::ScreencastInterface::Embedded) {
connect(KWin::Cursors::self(), &KWin::Cursors::positionChanged, this, [this] { connect(Cursors::self(), &Cursors::positionChanged, this, [this] {
if (m_cursor.lastFrameTexture) { if (m_cursor.lastFrameTexture) {
m_repainting = true; m_repainting = true;
recordFrame(m_cursor.lastFrameTexture.data(), QRegion{m_cursor.lastRect} | cursorGeometry(KWin::Cursors::self()->currentCursor())); recordFrame(m_cursor.lastFrameTexture.data(), QRegion{m_cursor.lastRect} | cursorGeometry(Cursors::self()->currentCursor()));
m_repainting = false; m_repainting = false;
} }
}); });
@ -291,9 +294,9 @@ void PipeWireStream::stop()
delete this; delete this;
} }
static KWin::GLTexture *copyTexture(KWin::GLTexture *texture) static GLTexture *copyTexture(GLTexture *texture)
{ {
KWin::GLTexture *copy = new KWin::GLTexture(texture->internalFormat(), texture->size()); GLTexture *copy = new GLTexture(texture->internalFormat(), texture->size());
copy->setFilter(GL_LINEAR); copy->setFilter(GL_LINEAR);
copy->setWrapMode(GL_CLAMP_TO_EDGE); copy->setWrapMode(GL_CLAMP_TO_EDGE);
@ -305,7 +308,7 @@ static KWin::GLTexture *copyTexture(KWin::GLTexture *texture)
return copy; return copy;
} }
void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &damagedRegion) void PipeWireStream::recordFrame(GLTexture *frameTexture, const QRegion &damagedRegion)
{ {
Q_ASSERT(!m_stopped); Q_ASSERT(!m_stopped);
Q_ASSERT(frameTexture); Q_ASSERT(frameTexture);
@ -320,7 +323,7 @@ void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &d
auto state = pw_stream_get_state(pwStream, &error); auto state = pw_stream_get_state(pwStream, &error);
if (state != PW_STREAM_STATE_STREAMING) { if (state != PW_STREAM_STATE_STREAMING) {
if (error) { if (error) {
qCWarning(KWIN_PIPEWIRE) << "Failed to record frame: stream is not active" << error; qCWarning(KWIN_SCREENCAST) << "Failed to record frame: stream is not active" << error;
} }
return; return;
} }
@ -336,7 +339,7 @@ void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &d
uint8_t *data = (uint8_t *) spa_data->data; uint8_t *data = (uint8_t *) spa_data->data;
if (!data && spa_buffer->datas->type != SPA_DATA_DmaBuf) { if (!data && spa_buffer->datas->type != SPA_DATA_DmaBuf) {
qCWarning(KWIN_PIPEWIRE) << "Failed to record frame: invalid buffer data"; qCWarning(KWIN_SCREENCAST) << "Failed to record frame: invalid buffer data";
pw_stream_queue_buffer(pwStream, buffer); pw_stream_queue_buffer(pwStream, buffer);
return; return;
} }
@ -349,7 +352,7 @@ void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &d
const uint bufferSize = stride * size.height(); const uint bufferSize = stride * size.height();
if (bufferSize > spa_data->maxsize) { if (bufferSize > spa_data->maxsize) {
qCDebug(KWIN_PIPEWIRE) << "Failed to record frame: frame is too big"; qCDebug(KWIN_SCREENCAST) << "Failed to record frame: frame is too big";
pw_stream_queue_buffer(pwStream, buffer); pw_stream_queue_buffer(pwStream, buffer);
return; return;
} }
@ -359,7 +362,7 @@ void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &d
frameTexture->bind(); frameTexture->bind();
glGetTextureImage(frameTexture->texture(), 0, m_hasAlpha ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, bufferSize, data); glGetTextureImage(frameTexture->texture(), 0, m_hasAlpha ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, bufferSize, data);
auto cursor = KWin::Cursors::self()->currentCursor(); auto cursor = Cursors::self()->currentCursor();
if (m_cursor.mode == KWaylandServer::ScreencastInterface::Embedded && m_cursor.viewport.contains(cursor->pos())) { if (m_cursor.mode == KWaylandServer::ScreencastInterface::Embedded && m_cursor.viewport.contains(cursor->pos())) {
QImage dest(data, size.width(), size.height(), QImage::Format_RGBA8888_Premultiplied); QImage dest(data, size.width(), size.height(), QImage::Format_RGBA8888_Premultiplied);
QPainter painter(&dest); QPainter painter(&dest);
@ -390,13 +393,13 @@ void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &d
frameTexture->render(damagedRegion, r, true); frameTexture->render(damagedRegion, r, true);
auto cursor = KWin::Cursors::self()->currentCursor(); auto cursor = Cursors::self()->currentCursor();
if (m_cursor.mode == KWaylandServer::ScreencastInterface::Embedded && m_cursor.viewport.contains(cursor->pos())) { if (m_cursor.mode == KWaylandServer::ScreencastInterface::Embedded && m_cursor.viewport.contains(cursor->pos())) {
if (!m_repainting) //We need to copy the last version of the stream to render the moved cursor on top if (!m_repainting) //We need to copy the last version of the stream to render the moved cursor on top
m_cursor.lastFrameTexture.reset(copyTexture(frameTexture)); m_cursor.lastFrameTexture.reset(copyTexture(frameTexture));
if (!m_cursor.texture || m_cursor.lastKey != cursor->image().cacheKey()) if (!m_cursor.texture || m_cursor.lastKey != cursor->image().cacheKey())
m_cursor.texture.reset(new KWin::GLTexture(cursor->image())); m_cursor.texture.reset(new GLTexture(cursor->image()));
m_cursor.texture->setYInverted(false); m_cursor.texture->setYInverted(false);
m_cursor.texture->bind(); m_cursor.texture->bind();
@ -418,20 +421,20 @@ void PipeWireStream::recordFrame(KWin::GLTexture* frameTexture, const QRegion &d
frameTexture->unbind(); frameTexture->unbind();
if (m_cursor.mode == KWaylandServer::ScreencastInterface::Metadata) { if (m_cursor.mode == KWaylandServer::ScreencastInterface::Metadata) {
sendCursorData(KWin::Cursors::self()->currentCursor(), sendCursorData(Cursors::self()->currentCursor(),
(spa_meta_cursor *) spa_buffer_find_meta_data (spa_buffer, SPA_META_Cursor, sizeof (spa_meta_cursor))); (spa_meta_cursor *) spa_buffer_find_meta_data (spa_buffer, SPA_META_Cursor, sizeof (spa_meta_cursor)));
} }
pw_stream_queue_buffer(pwStream, buffer); pw_stream_queue_buffer(pwStream, buffer);
} }
QRect PipeWireStream::cursorGeometry(KWin::Cursor *cursor) const QRect PipeWireStream::cursorGeometry(Cursor *cursor) const
{ {
const auto position = (cursor->pos() - m_cursor.viewport.topLeft() - cursor->hotspot()) * m_cursor.scale; const auto position = (cursor->pos() - m_cursor.viewport.topLeft() - cursor->hotspot()) * m_cursor.scale;
return QRect{position, m_cursor.texture->size()}; return QRect{position, m_cursor.texture->size()};
} }
void PipeWireStream::sendCursorData(KWin::Cursor* cursor, spa_meta_cursor *spa_meta_cursor) void PipeWireStream::sendCursorData(Cursor *cursor, spa_meta_cursor *spa_meta_cursor)
{ {
if (!cursor || !spa_meta_cursor) { if (!cursor || !spa_meta_cursor) {
return; return;
@ -476,3 +479,5 @@ void PipeWireStream::setCursorMode(KWaylandServer::ScreencastInterface::CursorMo
m_cursor.scale = scale; m_cursor.scale = scale;
m_cursor.viewport = viewport; m_cursor.viewport = viewport;
} }
} // namespace KWin

View File

@ -22,27 +22,27 @@
#pragma once #pragma once
#include <QObject> #include "config-kwin.h"
#include <QSize> #include "kwinglobals.h"
#include <QHash>
#include <QSharedPointer>
#include <KWaylandServer/screencast_interface.h> #include <KWaylandServer/screencast_interface.h>
#include "kwinglobals.h" #include <QHash>
#include "config-kwin.h" #include <QObject>
#include <QSharedPointer>
#include <QSize>
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include <spa/param/format-utils.h> #include <spa/param/format-utils.h>
#include <spa/param/video/format-utils.h>
#include <spa/param/props.h> #include <spa/param/props.h>
#include <spa/param/video/format-utils.h>
#undef Status
namespace KWin namespace KWin
{ {
class Cursor;
class GLTexture; class Cursor;
class DmaBufTexture; class DmaBufTexture;
} class GLTexture;
class PipeWireCore; class PipeWireCore;
class KWIN_EXPORT PipeWireStream : public QObject class KWIN_EXPORT PipeWireStream : public QObject
@ -62,7 +62,7 @@ public:
void stop(); void stop();
/** Renders @p frame into the current framebuffer into the stream */ /** Renders @p frame into the current framebuffer into the stream */
void recordFrame(KWin::GLTexture *frame, const QRegion &damagedRegion); void recordFrame(GLTexture *frame, const QRegion &damagedRegion);
void setCursorMode(KWaylandServer::ScreencastInterface::CursorMode mode, qreal scale, const QRect &viewport); void setCursorMode(KWaylandServer::ScreencastInterface::CursorMode mode, qreal scale, const QRect &viewport);
@ -80,7 +80,7 @@ private:
bool createStream(); bool createStream();
void updateParams(); void updateParams();
void coreFailed(const QString &errorMessage); void coreFailed(const QString &errorMessage);
void sendCursorData(KWin::Cursor* cursor, spa_meta_cursor *spa_cursor); void sendCursorData(Cursor *cursor, spa_meta_cursor *spa_cursor);
void newStreamParams(); void newStreamParams();
QSharedPointer<PipeWireCore> pwCore; QSharedPointer<PipeWireCore> pwCore;
@ -96,7 +96,6 @@ private:
spa_video_info_raw videoFormat; spa_video_info_raw videoFormat;
QString m_error; QString m_error;
const bool m_hasAlpha; const bool m_hasAlpha;
struct gbm_device *m_gbmDevice = nullptr;
struct { struct {
KWaylandServer::ScreencastInterface::CursorMode mode = KWaylandServer::ScreencastInterface::Hidden; KWaylandServer::ScreencastInterface::CursorMode mode = KWaylandServer::ScreencastInterface::Hidden;
@ -104,11 +103,13 @@ private:
QRect viewport; QRect viewport;
qint64 lastKey = 0; qint64 lastKey = 0;
QRect lastRect; QRect lastRect;
QScopedPointer<KWin::GLTexture> texture; QScopedPointer<GLTexture> texture;
QScopedPointer<KWin::GLTexture> lastFrameTexture; QScopedPointer<GLTexture> lastFrameTexture;
} m_cursor; } m_cursor;
bool m_repainting = false; bool m_repainting = false;
QRect cursorGeometry(KWin::Cursor *cursor) const; QRect cursorGeometry(Cursor *cursor) const;
QHash<struct pw_buffer *, QSharedPointer<KWin::DmaBufTexture>> m_dmabufDataForPwBuffer; QHash<struct pw_buffer *, QSharedPointer<DmaBufTexture>> m_dmabufDataForPwBuffer;
}; };
} // namespace KWin

View File

@ -36,7 +36,8 @@
#include <KWaylandServer/display.h> #include <KWaylandServer/display.h>
#include <KWaylandServer/output_interface.h> #include <KWaylandServer/output_interface.h>
using namespace KWin; namespace KWin
{
ScreencastManager::ScreencastManager(QObject *parent) ScreencastManager::ScreencastManager(QObject *parent)
: QObject(parent) : QObject(parent)
@ -53,7 +54,7 @@ class EGLFence : public QObject
public: public:
EGLFence(EGLDisplay eglDisplay) EGLFence(EGLDisplay eglDisplay)
: m_eglDisplay(eglDisplay) : m_eglDisplay(eglDisplay)
, m_sync(eglCreateSync(eglDisplay, EGL_SYNC_FENCE_KHR, NULL)) , m_sync(eglCreateSync(eglDisplay, EGL_SYNC_FENCE_KHR, nullptr))
{ {
Q_ASSERT(m_sync); Q_ASSERT(m_sync);
glFinish(); glFinish();
@ -80,7 +81,7 @@ private:
class WindowStream : public PipeWireStream class WindowStream : public PipeWireStream
{ {
public: public:
WindowStream(KWin::Toplevel *toplevel, QObject *parent) WindowStream(Toplevel *toplevel, QObject *parent)
: PipeWireStream(toplevel->hasAlpha(), toplevel->clientSize() * toplevel->bufferScale(), parent) : PipeWireStream(toplevel->hasAlpha(), toplevel->clientSize() * toplevel->bufferScale(), parent)
, m_toplevel(toplevel) , m_toplevel(toplevel)
{ {
@ -93,14 +94,14 @@ public:
private: private:
void startFeeding() { void startFeeding() {
auto scene = KWin::Compositor::self()->scene(); auto scene = Compositor::self()->scene();
connect(scene, &Scene::frameRendered, this, &WindowStream::bufferToStream); connect(scene, &Scene::frameRendered, this, &WindowStream::bufferToStream);
connect(m_toplevel, &Toplevel::damaged, this, &WindowStream::includeDamage); connect(m_toplevel, &Toplevel::damaged, this, &WindowStream::includeDamage);
m_toplevel->damaged(m_toplevel, m_toplevel->frameGeometry()); m_toplevel->damaged(m_toplevel, m_toplevel->frameGeometry());
} }
void includeDamage(KWin::Toplevel *toplevel, const QRect &damage) { void includeDamage(Toplevel *toplevel, const QRect &damage) {
Q_ASSERT(m_toplevel == toplevel); Q_ASSERT(m_toplevel == toplevel);
m_damagedRegion |= damage; m_damagedRegion |= damage;
} }
@ -122,12 +123,12 @@ private:
} }
QRegion m_damagedRegion; QRegion m_damagedRegion;
KWin::Toplevel *m_toplevel; Toplevel *m_toplevel;
}; };
void ScreencastManager::streamWindow(KWaylandServer::ScreencastStreamInterface *waylandStream, const QString &winid) void ScreencastManager::streamWindow(KWaylandServer::ScreencastStreamInterface *waylandStream, const QString &winid)
{ {
auto *toplevel = KWin::Workspace::self()->findToplevel(winid); auto *toplevel = Workspace::self()->findToplevel(winid);
if (!toplevel) { if (!toplevel) {
waylandStream->sendFailed(i18n("Could not find window id %1", winid)); waylandStream->sendFailed(i18n("Could not find window id %1", winid));
@ -166,7 +167,7 @@ void ScreencastManager::streamOutput(KWaylandServer::ScreencastStreamInterface *
stream->setCursorMode(mode, streamOutput->scale(), streamOutput->geometry()); stream->setCursorMode(mode, streamOutput->scale(), streamOutput->geometry());
connect(streamOutput, &QObject::destroyed, stream, &PipeWireStream::stopStreaming); connect(streamOutput, &QObject::destroyed, stream, &PipeWireStream::stopStreaming);
auto bufferToStream = [streamOutput, stream] (const QRegion &damagedRegion) { auto bufferToStream = [streamOutput, stream] (const QRegion &damagedRegion) {
auto scene = KWin::Compositor::self()->scene(); auto scene = Compositor::self()->scene();
auto texture = scene->textureForOutput(streamOutput); auto texture = scene->textureForOutput(streamOutput);
const QRect frame({}, streamOutput->modeSize()); const QRect frame({}, streamOutput->modeSize());
@ -174,7 +175,7 @@ void ScreencastManager::streamOutput(KWaylandServer::ScreencastStreamInterface *
stream->recordFrame(texture.data(), region); stream->recordFrame(texture.data(), region);
}; };
connect(stream, &PipeWireStream::startStreaming, waylandStream, [streamOutput, stream, bufferToStream] { connect(stream, &PipeWireStream::startStreaming, waylandStream, [streamOutput, stream, bufferToStream] {
KWin::Compositor::self()->addRepaint(streamOutput->geometry()); Compositor::self()->addRepaint(streamOutput->geometry());
connect(streamOutput, &AbstractWaylandOutput::outputChange, stream, bufferToStream); connect(streamOutput, &AbstractWaylandOutput::outputChange, stream, bufferToStream);
}); });
integrateStreams(waylandStream, stream); integrateStreams(waylandStream, stream);
@ -195,3 +196,5 @@ void ScreencastManager::integrateStreams(KWaylandServer::ScreencastStreamInterfa
delete stream; delete stream;
} }
} }
} // namespace KWin

View File

@ -23,6 +23,9 @@
#include <KWaylandServer/screencast_interface.h> #include <KWaylandServer/screencast_interface.h>
namespace KWin
{
class PipeWireStream; class PipeWireStream;
class ScreencastManager : public QObject class ScreencastManager : public QObject
@ -43,3 +46,4 @@ private:
KWaylandServer::ScreencastInterface *m_screencast; KWaylandServer::ScreencastInterface *m_screencast;
}; };
} // namespace KWin