30#include <QQuickWindow>
43WaylandCompositor::WaylandCompositor(QObject *parent)
54bool WaylandCompositor::attemptOpenGLCompositing()
56 std::unique_ptr<OpenGLBackend>
backend = kwinApp()->outputBackend()->createOpenGLBackend();
67 const QByteArray forceEnv = qgetenv(
"KWIN_COMPOSE");
68 if (!forceEnv.isEmpty()) {
69 if (qstrcmp(forceEnv,
"O2") == 0 || qstrcmp(forceEnv,
"O2ES") == 0) {
70 qCDebug(KWIN_CORE) <<
"OpenGL 2 compositing enforced by environment variable";
77 qCDebug(KWIN_CORE) <<
"Driver does not recommend OpenGL compositing";
84 qCDebug(KWIN_CORE) <<
"OpenGL 2.0 is not supported";
89 m_cursorScene = std::make_unique<CursorScene>(std::make_unique<ItemRendererOpenGL>());
92 qCDebug(KWIN_CORE) <<
"OpenGL compositing has been successfully initialized";
96bool WaylandCompositor::attemptQPainterCompositing()
98 std::unique_ptr<QPainterBackend>
backend(kwinApp()->outputBackend()->createQPainterBackend());
103 m_scene = std::make_unique<WorkspaceSceneQPainter>(
backend.get());
104 m_cursorScene = std::make_unique<CursorScene>(std::make_unique<ItemRendererQPainter>());
107 qCDebug(KWIN_CORE) <<
"QPainter compositing has been successfully initialized";
113 if (kwinApp()->isTerminating()) {
124 const QList<CompositingType> availableCompositors = kwinApp()->outputBackend()->supportedCompositors();
125 QList<CompositingType> candidateCompositors;
128 candidateCompositors.append(m_selectedCompositor);
130 candidateCompositors = availableCompositors;
132 const auto userConfigIt = std::find(candidateCompositors.begin(), candidateCompositors.end(),
options->
compositingMode());
133 if (userConfigIt != candidateCompositors.end()) {
134 candidateCompositors.erase(userConfigIt);
137 qCWarning(KWIN_CORE) <<
"Configured compositor not supported by Platform. Falling back to defaults";
141 for (
auto type : std::as_const(candidateCompositors)) {
145 qCDebug(KWIN_CORE) <<
"Attempting to load the OpenGL scene";
146 stop = attemptOpenGLCompositing();
149 qCDebug(KWIN_CORE) <<
"Attempting to load the QPainter scene";
150 stop = attemptQPainterCompositing();
153 qCDebug(KWIN_CORE) <<
"Starting without compositing...";
160 }
else if (qEnvironmentVariableIsSet(
"KWIN_COMPOSE")) {
161 qCCritical(KWIN_CORE) <<
"Could not fulfill the requested compositing mode in KWIN_COMPOSE:" <<
type <<
". Exiting.";
169 qCCritical(KWIN_CORE) <<
"The used windowing system requires compositing";
170 qCCritical(KWIN_CORE) <<
"We are going to quit KWin now as it is broken";
176 m_selectedCompositor =
m_backend->compositingType();
178 switch (m_selectedCompositor) {
182 QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
185 QQuickWindow::setGraphicsApi(QSGRendererInterface::Software);
193 for (
Output *output : outputs) {
202 for (
Window *window : windows) {
203 window->setupCompositing();
207 kwinApp()->createEffectsHandler(
this,
m_scene.get());
228 for (
Window *window : windows) {
229 window->finishCompositing();
241 for (
auto it = superlayers.begin(); it != superlayers.end(); ++it) {
253void WaylandCompositor::addOutput(
Output *output)
258 auto workspaceLayer =
new RenderLayer(output->
renderLoop());
259 workspaceLayer->setDelegate(std::make_unique<SceneDelegate>(
m_scene.get(), output));
260 workspaceLayer->setGeometry(output->
rectF());
262 workspaceLayer->setGeometry(output->
rectF());
265 auto cursorLayer =
new RenderLayer(output->
renderLoop());
266 cursorLayer->setVisible(
false);
268 cursorLayer->setDelegate(std::make_unique<CursorDelegateOpenGL>(output));
270 cursorLayer->setDelegate(std::make_unique<CursorDelegateQPainter>(output));
272 cursorLayer->setParent(workspaceLayer);
273 cursorLayer->setSuperlayer(workspaceLayer);
277 static bool forceSoftwareCursorIsSet;
278 static const bool forceSoftwareCursor = qEnvironmentVariableIntValue(
"KWIN_FORCE_SW_CURSOR", &forceSoftwareCursorIsSet) == 1
281 auto updateCursorLayer = [
this, output, cursorLayer]() {
283 const QRectF outputLocalRect = output->
mapFromGlobal(cursor->geometry());
284 const auto outputLayer =
m_backend->cursorLayer(output);
285 if (!cursor->isOnOutput(output)) {
286 if (outputLayer && outputLayer->isEnabled()) {
287 outputLayer->setEnabled(
false);
290 cursorLayer->setVisible(
false);
293 const auto renderHardwareCursor = [&]() {
294 if (!outputLayer || forceSoftwareCursor) {
298 QSize bufferSize(std::ceil(nativeCursorRect.width()), std::ceil(nativeCursorRect.height()));
299 if (
const auto fixedSize = outputLayer->fixedSize()) {
300 if (fixedSize->width() < bufferSize.width() || fixedSize->height() < bufferSize.height()) {
303 bufferSize = *fixedSize;
304 nativeCursorRect = output->
transform().
map(QRectF(outputLocalRect.topLeft() * output->
scale(), bufferSize), output->
pixelSize());
306 outputLayer->setPosition(nativeCursorRect.topLeft());
307 outputLayer->setHotspot(output->
transform().
map(cursor->hotspot() * output->
scale(), bufferSize));
308 outputLayer->setSize(bufferSize);
309 if (
auto beginInfo = outputLayer->beginFrame()) {
310 const RenderTarget &renderTarget = beginInfo->renderTarget;
312 RenderLayer renderLayer(output->
renderLoop());
313 renderLayer.setDelegate(std::make_unique<SceneDelegate>(
m_cursorScene.get(), output));
314 renderLayer.setOutputLayer(outputLayer);
316 renderLayer.delegate()->prePaint();
318 renderLayer.delegate()->postPaint();
326 outputLayer->setEnabled(
true);
329 if (renderHardwareCursor()) {
330 cursorLayer->setVisible(
false);
333 if (outputLayer && outputLayer->isEnabled()) {
334 outputLayer->setEnabled(
false);
337 cursorLayer->setVisible(cursor->isOnOutput(output));
338 cursorLayer->setGeometry(outputLocalRect);
339 cursorLayer->addRepaintFull();
343 auto moveCursorLayer = [
this, output, cursorLayer, updateCursorLayer]() {
345 const QRectF outputLocalRect = output->
mapFromGlobal(cursor->geometry());
346 const auto outputLayer =
m_backend->cursorLayer(output);
347 bool hardwareCursor =
false;
349 if (outputLayer->isEnabled()) {
350 const QRectF nativeCursorRect = output->
transform()
351 .
map(QRectF(outputLocalRect.topLeft() * output->
scale(), outputLayer->size()), output->
pixelSize());
352 outputLayer->setPosition(nativeCursorRect.topLeft());
354 }
else if (!cursorLayer->isVisible() && !forceSoftwareCursor) {
356 hardwareCursor = updateCursorLayer();
359 cursorLayer->setVisible(cursor->isOnOutput(output) && !hardwareCursor);
360 cursorLayer->setGeometry(outputLocalRect);
361 cursorLayer->addRepaintFull();
372void WaylandCompositor::removeOutput(Output *output)
374 if (output->isPlaceholder()) {
382#include "moc_compositor_wayland.cpp"
void compositingToggled(bool active)
static Compositor * s_compositor
std::unique_ptr< RenderBackend > m_backend
std::unique_ptr< CursorScene > m_cursorScene
void aboutToToggleCompositing()
void removeSuperLayer(RenderLayer *layer)
RenderBackend * backend() const
std::unique_ptr< WorkspaceScene > m_scene
QHash< RenderLoop *, RenderLayer * > m_superlayers
void addSuperLayer(RenderLayer *layer)
void positionChanged(Cursor *cursor, const QPointF &position)
void currentCursorChanged(Cursor *cursor)
Cursor * currentCursor() const
The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap.
bool isPlaceholder() const
OutputTransform transform() const
QRect mapFromGlobal(const QRect &rect) const
virtual RenderLoop * renderLoop() const =0
virtual bool updateCursorLayer()
~WaylandCompositor() override
static WaylandCompositor * create(QObject *parent=nullptr)
void outputAdded(KWin::Output *)
static Workspace * self()
QList< Output * > outputs() const
const QList< Window * > windows() const
void outputRemoved(KWin::Output *)
KWIN_EXPORT QRect infiniteRegion()
bool hasGLVersion(int major, int minor, int release)
KWIN_EXPORT QRectF scaledRect(const QRectF &rect, qreal scale)