screencasting: Minimise pixel format conversions while streaming
Instead of best-guessing, at BGR (which in retrospect was a bad guess), offer whatever resembles most the internal representation. This way the frame gets to be least treated as it goes into the client.
This commit is contained in:
parent
4fcc545628
commit
150b098ba7
37 changed files with 226 additions and 29 deletions
|
@ -7,6 +7,7 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "drm_egl_cursor_layer.h"
|
||||
#include "drm_buffer.h"
|
||||
#include "drm_egl_backend.h"
|
||||
#include "drm_gpu.h"
|
||||
#include "drm_pipeline.h"
|
||||
|
@ -57,4 +58,8 @@ void EglGbmCursorLayer::releaseBuffers()
|
|||
m_surface.destroyResources();
|
||||
}
|
||||
|
||||
quint32 EglGbmCursorLayer::format() const
|
||||
{
|
||||
return m_surface.currentBuffer()->buffer()->format();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
QRegion currentDamage() const override;
|
||||
bool checkTestBuffer() override;
|
||||
void releaseBuffers() override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
EglGbmLayerSurface m_surface;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "drm_pipeline.h"
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -21,6 +22,11 @@ QRegion DrmOutputLayer::currentDamage() const
|
|||
return {};
|
||||
}
|
||||
|
||||
quint32 DrmOutputLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
std::shared_ptr<GLTexture> DrmOutputLayer::texture() const
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
virtual std::shared_ptr<GLTexture> texture() const;
|
||||
virtual QRegion currentDamage() const;
|
||||
virtual void releaseBuffers() = 0;
|
||||
quint32 format() const override;
|
||||
};
|
||||
|
||||
class DrmPipelineLayer : public DrmOutputLayer
|
||||
|
|
|
@ -92,6 +92,11 @@ void DrmQPainterLayer::releaseBuffers()
|
|||
m_swapchain.reset();
|
||||
}
|
||||
|
||||
quint32 DrmQPainterLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
}
|
||||
|
||||
DrmCursorQPainterLayer::DrmCursorQPainterLayer(DrmPipeline *pipeline)
|
||||
: DrmOverlayLayer(pipeline)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
std::shared_ptr<DrmFramebuffer> currentBuffer() const override;
|
||||
QRegion currentDamage() const override;
|
||||
void releaseBuffers() override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
bool doesSwapchainFit() const;
|
||||
|
|
|
@ -175,4 +175,9 @@ void VirtualEglGbmLayer::releaseBuffers()
|
|||
m_gbmSurface.reset();
|
||||
m_oldGbmSurface.reset();
|
||||
}
|
||||
|
||||
quint32 VirtualEglGbmLayer::format() const
|
||||
{
|
||||
return m_gbmSurface->format();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
QRegion currentDamage() const override;
|
||||
std::shared_ptr<GLTexture> texture() const override;
|
||||
void releaseBuffers() override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
bool createGbmSurface();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "virtual_backend.h"
|
||||
#include "virtual_output.h"
|
||||
// kwin libs
|
||||
#include <drm_fourcc.h>
|
||||
#include <kwinglutils.h>
|
||||
|
||||
#ifndef EGL_PLATFORM_SURFACELESS_MESA
|
||||
|
@ -61,6 +62,12 @@ bool VirtualEglLayer::endFrame(const QRegion &renderedRegion, const QRegion &dam
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 VirtualEglLayer::format() const
|
||||
{
|
||||
// the texture format is hardcoded in VirtualEglLayer::beginFrame
|
||||
return DRM_FORMAT_RGB888;
|
||||
}
|
||||
|
||||
VirtualEglBackend::VirtualEglBackend(VirtualBackend *b)
|
||||
: AbstractEglBackend()
|
||||
, m_backend(b)
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
||||
std::shared_ptr<GLTexture> texture() const;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
VirtualEglBackend *const m_backend;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "virtual_output.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -41,6 +42,11 @@ QImage *VirtualQPainterLayer::image()
|
|||
return &m_image;
|
||||
}
|
||||
|
||||
quint32 VirtualQPainterLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBX8888;
|
||||
}
|
||||
|
||||
VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
|
||||
{
|
||||
connect(backend, &VirtualBackend::outputAdded, this, &VirtualQPainterBackend::addOutput);
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
QImage *image();
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
Output *const m_output;
|
||||
|
|
|
@ -125,6 +125,11 @@ int WaylandEglLayerBuffer::age() const
|
|||
return m_age;
|
||||
}
|
||||
|
||||
gbm_bo *WaylandEglLayerBuffer::bo() const
|
||||
{
|
||||
return m_bo;
|
||||
}
|
||||
|
||||
WaylandEglLayerSwapchain::WaylandEglLayerSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, WaylandEglBackend *backend)
|
||||
: m_backend(backend)
|
||||
, m_size(size)
|
||||
|
@ -284,6 +289,16 @@ bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegio
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 WaylandEglCursorLayer::format() const
|
||||
{
|
||||
return gbm_bo_get_format(m_buffer->bo());
|
||||
}
|
||||
|
||||
quint32 WaylandEglPrimaryLayer::format() const
|
||||
{
|
||||
return gbm_bo_get_format(m_buffer->bo());
|
||||
}
|
||||
|
||||
WaylandEglBackend::WaylandEglBackend(WaylandBackend *b)
|
||||
: AbstractEglBackend()
|
||||
, m_backend(b)
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
GLFramebuffer *framebuffer() const;
|
||||
std::shared_ptr<GLTexture> texture() const;
|
||||
int age() const;
|
||||
gbm_bo *bo() const;
|
||||
|
||||
private:
|
||||
WaylandEglBackend *m_backend;
|
||||
|
@ -83,6 +84,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
WaylandOutput *m_waylandOutput;
|
||||
|
@ -104,6 +106,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
WaylandOutput *m_output;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -129,6 +130,11 @@ bool WaylandQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 WaylandQPainterPrimaryLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output)
|
||||
: m_output(output)
|
||||
{
|
||||
|
@ -159,6 +165,11 @@ bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const Q
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 WaylandQPainterCursorLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
|
||||
: QPainterBackend()
|
||||
, m_backend(b)
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
void remapBuffer();
|
||||
|
||||
|
@ -88,6 +89,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
WaylandOutput *m_output;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QtPlatformHeaders/QEGLNativeContext>
|
||||
#endif
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -43,6 +44,11 @@ bool EglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedReg
|
|||
return true;
|
||||
}
|
||||
|
||||
uint EglLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
EglBackend::EglBackend(Display *display, X11StandaloneBackend *backend)
|
||||
: EglOnXBackend(kwinApp()->x11Connection(), display, kwinApp()->x11RootWindow())
|
||||
, m_backend(backend)
|
||||
|
@ -162,7 +168,6 @@ OutputLayerBeginFrameInfo EglBackend::beginFrame()
|
|||
if (supportsBufferAge()) {
|
||||
repaint = m_damageJournal.accumulate(m_bufferAge, infiniteRegion());
|
||||
}
|
||||
|
||||
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
|
||||
|
||||
return OutputLayerBeginFrameInfo{
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
uint format() const override;
|
||||
|
||||
private:
|
||||
EglBackend *const m_backend;
|
||||
|
|
|
@ -74,6 +74,7 @@ typedef struct xcb_glx_buffer_swap_complete_event_t
|
|||
} xcb_glx_buffer_swap_complete_event_t;
|
||||
#endif
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
#include <tuple>
|
||||
|
||||
namespace KWin
|
||||
|
@ -120,6 +121,11 @@ bool GlxLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedReg
|
|||
return true;
|
||||
}
|
||||
|
||||
uint GlxLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
GlxBackend::GlxBackend(Display *display, X11StandaloneBackend *backend)
|
||||
: OpenGLBackend()
|
||||
, m_overlayWindow(std::make_unique<OverlayWindowX11>())
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
uint format() const override;
|
||||
|
||||
private:
|
||||
GlxBackend *const m_backend;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "x11_windowed_backend.h"
|
||||
#include "x11_windowed_output.h"
|
||||
// kwin libs
|
||||
#include <drm_fourcc.h>
|
||||
#include <kwinglplatform.h>
|
||||
|
||||
namespace KWin
|
||||
|
@ -72,6 +73,11 @@ GLFramebuffer *X11WindowedEglPrimaryLayer::fbo() const
|
|||
return m_fbo.get();
|
||||
}
|
||||
|
||||
quint32 X11WindowedEglPrimaryLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
X11WindowedEglCursorLayer::X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output)
|
||||
: m_output(output)
|
||||
, m_backend(backend)
|
||||
|
@ -115,6 +121,11 @@ bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QR
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 X11WindowedEglCursorLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
X11WindowedEglBackend::X11WindowedEglBackend(X11WindowedBackend *backend)
|
||||
: EglOnXBackend(backend->connection(), backend->display(), backend->rootWindow())
|
||||
, m_backend(backend)
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
EGLSurface surface() const;
|
||||
QRegion lastDamage() const;
|
||||
GLFramebuffer *fbo() const;
|
||||
|
@ -54,6 +55,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
X11WindowedOutput *const m_output;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <cerrno>
|
||||
#include <cmath>
|
||||
#include <drm_fourcc.h>
|
||||
#include <string.h>
|
||||
#include <sys/shm.h>
|
||||
#include <xcb/present.h>
|
||||
|
@ -173,6 +174,17 @@ void X11WindowedQPainterPrimaryLayer::present()
|
|||
m_swapchain->release(m_buffer);
|
||||
}
|
||||
|
||||
quint32 X11WindowedQPainterPrimaryLayer::format() const
|
||||
{
|
||||
switch (m_buffer->view()->format()) {
|
||||
case QImage::Format_A2RGB30_Premultiplied:
|
||||
return DRM_FORMAT_ARGB2101010;
|
||||
case QImage::Format_ARGB32_Premultiplied:
|
||||
default:
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
}
|
||||
}
|
||||
|
||||
X11WindowedQPainterCursorLayer::X11WindowedQPainterCursorLayer(X11WindowedOutput *output)
|
||||
: m_output(output)
|
||||
{
|
||||
|
@ -192,6 +204,11 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterCursorLayer::beginFr
|
|||
};
|
||||
}
|
||||
|
||||
quint32 X11WindowedQPainterCursorLayer::format() const
|
||||
{
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
}
|
||||
|
||||
bool X11WindowedQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
m_output->cursor()->update(m_buffer, hotspot());
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
void present();
|
||||
|
||||
|
@ -84,6 +85,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
private:
|
||||
QImage m_buffer;
|
||||
|
|
|
@ -638,6 +638,12 @@ void Compositor::handleFrameRequested(RenderLoop *renderLoop)
|
|||
composite(renderLoop);
|
||||
}
|
||||
|
||||
uint Compositor::outputFormat(Output *output)
|
||||
{
|
||||
OutputLayer *primaryLayer = m_backend->primaryLayer(output);
|
||||
return primaryLayer->format();
|
||||
}
|
||||
|
||||
void Compositor::composite(RenderLoop *renderLoop)
|
||||
{
|
||||
if (m_backend->checkGraphicsReset()) {
|
||||
|
|
|
@ -139,6 +139,13 @@ public:
|
|||
*/
|
||||
virtual void createOpenGLSafePoint(OpenGLSafePoint safePoint);
|
||||
|
||||
/**
|
||||
* @returns the format of the contents in the @p output
|
||||
*
|
||||
* This format is provided using the drm fourcc encoding
|
||||
*/
|
||||
uint outputFormat(Output *output);
|
||||
|
||||
Q_SIGNALS:
|
||||
void compositingToggled(bool active);
|
||||
void aboutToDestroy();
|
||||
|
|
|
@ -53,6 +53,11 @@ public:
|
|||
virtual std::optional<OutputLayerBeginFrameInfo> beginFrame() = 0;
|
||||
virtual bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0;
|
||||
|
||||
/**
|
||||
* Format in which the output data is internally stored in a drm fourcc format
|
||||
*/
|
||||
virtual quint32 format() const = 0;
|
||||
|
||||
/**
|
||||
* Tries to import the newest buffer of the surface for direct scanout
|
||||
* Returns @c true if scanout succeeds, @c false if rendering is necessary
|
||||
|
|
|
@ -29,6 +29,11 @@ bool OutputScreenCastSource::hasAlphaChannel() const
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 OutputScreenCastSource::drmFormat() const
|
||||
{
|
||||
return Compositor::self()->outputFormat(m_output);
|
||||
}
|
||||
|
||||
QSize OutputScreenCastSource::textureSize() const
|
||||
{
|
||||
return m_output->pixelSize();
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
|
||||
bool hasAlphaChannel() const override;
|
||||
QSize textureSize() const override;
|
||||
quint32 drmFormat() const override;
|
||||
|
||||
void render(GLFramebuffer *target) override;
|
||||
void render(QImage *image) override;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <composite.h>
|
||||
#include <core/output.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <kwingltexture.h>
|
||||
#include <kwinglutils.h>
|
||||
#include <scene/workspacescene.h>
|
||||
|
@ -38,6 +39,11 @@ bool RegionScreenCastSource::hasAlphaChannel() const
|
|||
return true;
|
||||
}
|
||||
|
||||
quint32 RegionScreenCastSource::drmFormat() const
|
||||
{
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
}
|
||||
|
||||
void RegionScreenCastSource::updateOutput(Output *output)
|
||||
{
|
||||
m_last = output->renderLoop()->lastPresentationTimestamp();
|
||||
|
@ -73,7 +79,7 @@ std::chrono::nanoseconds RegionScreenCastSource::clock() const
|
|||
void RegionScreenCastSource::ensureTexture()
|
||||
{
|
||||
if (!m_renderedTexture) {
|
||||
m_renderedTexture.reset(new GLTexture(hasAlphaChannel() ? GL_RGBA8 : GL_RGB8, textureSize()));
|
||||
m_renderedTexture.reset(new GLTexture(GL_RGBA8, textureSize()));
|
||||
m_target.reset(new GLFramebuffer(m_renderedTexture.get()));
|
||||
const auto allOutputs = workspace()->outputs();
|
||||
for (auto output : allOutputs) {
|
||||
|
|
|
@ -23,6 +23,7 @@ class RegionScreenCastSource : public ScreenCastSource
|
|||
public:
|
||||
explicit RegionScreenCastSource(const QRect ®ion, qreal scale, QObject *parent = nullptr);
|
||||
|
||||
quint32 drmFormat() const override;
|
||||
bool hasAlphaChannel() const override;
|
||||
QSize textureSize() const override;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ public:
|
|||
explicit ScreenCastSource(QObject *parent = nullptr);
|
||||
|
||||
virtual bool hasAlphaChannel() const = 0;
|
||||
virtual quint32 drmFormat() const = 0;
|
||||
virtual QSize textureSize() const = 0;
|
||||
|
||||
virtual void render(GLFramebuffer *target) = 0;
|
||||
|
|
|
@ -41,24 +41,30 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
uint32_t spaVideoFormatToDrmFormat(spa_video_format spa_format)
|
||||
static spa_video_format drmFourCCToSpaVideoFormat(quint32 format)
|
||||
{
|
||||
switch (spa_format) {
|
||||
case SPA_VIDEO_FORMAT_RGBA:
|
||||
return DRM_FORMAT_ABGR8888;
|
||||
case SPA_VIDEO_FORMAT_RGBx:
|
||||
return DRM_FORMAT_XBGR8888;
|
||||
case SPA_VIDEO_FORMAT_BGRA:
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
case SPA_VIDEO_FORMAT_BGRx:
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
case SPA_VIDEO_FORMAT_BGR:
|
||||
return DRM_FORMAT_BGR888;
|
||||
case SPA_VIDEO_FORMAT_RGB:
|
||||
return DRM_FORMAT_RGB888;
|
||||
switch (format) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return SPA_VIDEO_FORMAT_BGRA;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return SPA_VIDEO_FORMAT_BGRx;
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
return SPA_VIDEO_FORMAT_ABGR;
|
||||
case DRM_FORMAT_RGBX8888:
|
||||
return SPA_VIDEO_FORMAT_xBGR;
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
return SPA_VIDEO_FORMAT_RGBA;
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
return SPA_VIDEO_FORMAT_RGBx;
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
return SPA_VIDEO_FORMAT_ARGB;
|
||||
case DRM_FORMAT_BGRX8888:
|
||||
return SPA_VIDEO_FORMAT_xRGB;
|
||||
case DRM_FORMAT_NV12:
|
||||
return SPA_VIDEO_FORMAT_NV12;
|
||||
default:
|
||||
qCDebug(KWIN_SCREENCAST) << "unknown format" << spa_format;
|
||||
return DRM_FORMAT_INVALID;
|
||||
qCDebug(KWIN_SCREENCAST) << "unknown format" << format;
|
||||
return SPA_VIDEO_FORMAT_xRGB;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,9 +164,9 @@ void ScreenCastStream::onStreamParamChanged(void *data, uint32_t id, const struc
|
|||
}
|
||||
if (modifierProperty && (!pw->m_dmabufParams || !receivedModifiers.contains(pw->m_dmabufParams->modifier))) {
|
||||
if (modifierProperty->flags & SPA_POD_PROP_FLAG_DONT_FIXATE) {
|
||||
pw->m_dmabufParams = kwinApp()->outputBackend()->testCreateDmaBuf(pw->m_resolution, spaVideoFormatToDrmFormat(pw->videoFormat.format), receivedModifiers);
|
||||
pw->m_dmabufParams = kwinApp()->outputBackend()->testCreateDmaBuf(pw->m_resolution, pw->m_drmFormat, receivedModifiers);
|
||||
} else {
|
||||
pw->m_dmabufParams = kwinApp()->outputBackend()->testCreateDmaBuf(pw->m_resolution, spaVideoFormatToDrmFormat(pw->videoFormat.format), {DRM_FORMAT_MOD_INVALID});
|
||||
pw->m_dmabufParams = kwinApp()->outputBackend()->testCreateDmaBuf(pw->m_resolution, pw->m_drmFormat, {DRM_FORMAT_MOD_INVALID});
|
||||
}
|
||||
|
||||
qCDebug(KWIN_SCREENCAST) << "Stream dmabuf modifiers received, offering our best suited modifier" << pw->m_dmabufParams.has_value();
|
||||
|
@ -333,11 +339,25 @@ bool ScreenCastStream::createStream()
|
|||
const QByteArray objname = "kwin-screencast-" + objectName().toUtf8();
|
||||
pwStream = pw_stream_new(pwCore->pwCore, objname, nullptr);
|
||||
|
||||
// it could make sense to offer the same format as the source
|
||||
const auto format = m_source->hasAlphaChannel() ? SPA_VIDEO_FORMAT_BGRA : SPA_VIDEO_FORMAT_BGR;
|
||||
const int drmFormat = spaVideoFormatToDrmFormat(format);
|
||||
m_hasDmaBuf = kwinApp()->outputBackend()->testCreateDmaBuf(m_resolution, drmFormat, {DRM_FORMAT_MOD_INVALID}).has_value();
|
||||
m_modifiers = Compositor::self()->backend()->supportedFormats().value(drmFormat);
|
||||
const auto supported = Compositor::self()->backend()->supportedFormats();
|
||||
auto itModifiers = supported.constFind(m_source->drmFormat());
|
||||
|
||||
// If the offered format is not available for dmabuf, prefer converting to another one than resorting to memfd
|
||||
if (itModifiers == supported.constEnd() && !supported.isEmpty()) {
|
||||
itModifiers = supported.constFind(DRM_FORMAT_ARGB8888);
|
||||
if (itModifiers == supported.constEnd()) {
|
||||
m_drmFormat = itModifiers.key();
|
||||
}
|
||||
}
|
||||
|
||||
if (itModifiers == supported.constEnd()) {
|
||||
m_drmFormat = m_source->drmFormat();
|
||||
m_modifiers = {};
|
||||
} else {
|
||||
m_drmFormat = itModifiers.key();
|
||||
m_modifiers = *itModifiers;
|
||||
}
|
||||
m_hasDmaBuf = kwinApp()->outputBackend()->testCreateDmaBuf(m_resolution, m_drmFormat, {DRM_FORMAT_MOD_INVALID}).has_value();
|
||||
|
||||
char buffer[2048];
|
||||
QVector<const spa_pod *> params = buildFormats(false, buffer);
|
||||
|
@ -633,7 +653,7 @@ void ScreenCastStream::enqueue()
|
|||
|
||||
QVector<const spa_pod *> ScreenCastStream::buildFormats(bool fixate, char buffer[2048])
|
||||
{
|
||||
const auto format = m_source->hasAlphaChannel() ? SPA_VIDEO_FORMAT_BGRA : SPA_VIDEO_FORMAT_BGR;
|
||||
const auto format = drmFourCCToSpaVideoFormat(m_drmFormat);
|
||||
spa_pod_builder podBuilder = SPA_POD_BUILDER_INIT(buffer, 2048);
|
||||
spa_fraction minFramerate = SPA_FRACTION(1, 1);
|
||||
spa_fraction maxFramerate = SPA_FRACTION(25, 1);
|
||||
|
@ -672,6 +692,9 @@ spa_pod *ScreenCastStream::buildFormat(struct spa_pod_builder *b, enum spa_video
|
|||
if (format == SPA_VIDEO_FORMAT_BGRA) {
|
||||
/* announce equivalent format without alpha */
|
||||
spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(3, format, format, SPA_VIDEO_FORMAT_BGRx), 0);
|
||||
} else if (format == SPA_VIDEO_FORMAT_RGBA) {
|
||||
/* announce equivalent format without alpha */
|
||||
spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(3, format, format, SPA_VIDEO_FORMAT_RGBx), 0);
|
||||
} else {
|
||||
spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0);
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ private:
|
|||
quint64 m_sequential = 0;
|
||||
bool m_hasDmaBuf = false;
|
||||
bool m_waitForNewBuffers = false;
|
||||
quint32 m_drmFormat = 0;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -25,6 +25,24 @@ static void mirrorVertically(uchar *data, int height, int stride)
|
|||
}
|
||||
}
|
||||
|
||||
static GLenum closestGLType(const QImage &image)
|
||||
{
|
||||
switch (image.format()) {
|
||||
case QImage::Format_RGB888:
|
||||
return GL_RGB;
|
||||
case QImage::Format_BGR888:
|
||||
return GL_BGR;
|
||||
case QImage::Format_RGB32:
|
||||
case QImage::Format_RGBX8888:
|
||||
case QImage::Format_RGBA8888:
|
||||
case QImage::Format_RGBA8888_Premultiplied:
|
||||
return GL_RGBA;
|
||||
default:
|
||||
qDebug() << "unknown format" << image.format();
|
||||
return GL_RGBA;
|
||||
}
|
||||
}
|
||||
|
||||
static void grabTexture(GLTexture *texture, QImage *image)
|
||||
{
|
||||
const bool invert = !texture->isYInverted();
|
||||
|
@ -40,11 +58,11 @@ static void grabTexture(GLTexture *texture, QImage *image)
|
|||
|
||||
texture->bind();
|
||||
if (GLPlatform::instance()->isGLES()) {
|
||||
glReadPixels(0, 0, image->width(), image->height(), image->hasAlphaChannel() ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, (GLvoid *)image->bits());
|
||||
glReadPixels(0, 0, image->width(), image->height(), closestGLType(*image), GL_UNSIGNED_BYTE, (GLvoid *)image->bits());
|
||||
} else if (GLPlatform::instance()->glVersion() >= kVersionNumber(4, 5)) {
|
||||
glGetTextureImage(texture->texture(), 0, image->hasAlphaChannel() ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, image->sizeInBytes(), image->bits());
|
||||
glGetTextureImage(texture->texture(), 0, closestGLType(*image), GL_UNSIGNED_BYTE, image->sizeInBytes(), image->bits());
|
||||
} else {
|
||||
glGetTexImage(texture->target(), 0, image->hasAlphaChannel() ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, image->bits());
|
||||
glGetTexImage(texture->target(), 0, closestGLType(*image), GL_UNSIGNED_BYTE, image->bits());
|
||||
}
|
||||
|
||||
if (invertNeededAndSupported) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "scene/itemrenderer.h"
|
||||
#include "scene/windowitem.h"
|
||||
#include "scene/workspacescene.h"
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -30,6 +31,11 @@ WindowScreenCastSource::WindowScreenCastSource(Window *window, QObject *parent)
|
|||
connect(m_window, &Window::windowClosed, this, &ScreenCastSource::closed);
|
||||
}
|
||||
|
||||
quint32 WindowScreenCastSource::drmFormat() const
|
||||
{
|
||||
return DRM_FORMAT_RGBA8888;
|
||||
}
|
||||
|
||||
bool WindowScreenCastSource::hasAlphaChannel() const
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -22,6 +22,7 @@ class WindowScreenCastSource : public ScreenCastSource
|
|||
public:
|
||||
explicit WindowScreenCastSource(Window *window, QObject *parent = nullptr);
|
||||
|
||||
quint32 drmFormat() const override;
|
||||
bool hasAlphaChannel() const override;
|
||||
QSize textureSize() const override;
|
||||
|
||||
|
|
Loading…
Reference in a new issue