From 9f47021a307781a0c2cecffd3706d1a8f4cce505 Mon Sep 17 00:00:00 2001
From: Eduardo Hopperdietzel
Date: Mon, 27 Jan 2025 18:08:47 -0300
Subject: [PATCH] Update version to 2.14.0-1
---
CHANGES | 9 +++++++++
README.md | 2 +-
VERSION | 2 +-
pkg/fedora/latest.spec | 12 +++---------
src/lib/core/LCompositor.cpp | 8 ++++----
src/lib/core/LOutput.cpp | 1 +
src/lib/core/LOutput.h | 13 ++++++++++---
src/lib/core/private/LCompositorPrivate.cpp | 9 +++++++++
src/lib/core/private/LOutputPrivate.cpp | 8 ++++++++
src/lib/core/private/LSeatPrivate.cpp | 18 ++++++++++++++++++
10 files changed, 64 insertions(+), 18 deletions(-)
diff --git a/CHANGES b/CHANGES
index a7d1e3fa..a2944cc5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+Louvre (2.14.0-1)
+
+ # API Additions
+
+ - LOutput::repaintFilter(): Intercepts LOutput::repaint() calls, making it easier to retain the last rendered frame. Special thanks to @LeKinaSa and @jgroboredo for highlighting the need for this feature.
+
+-- Eduardo Hopperdietzel Mon, 27 Jan 2025 17:47:20 -0300
+
+
Louvre (2.13.0-1)
# License
diff --git a/README.md b/README.md
index 944ef7ae..110818e6 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
-
+
diff --git a/VERSION b/VERSION
index fb2c0766..edcfe40d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.13.0
+2.14.0
diff --git a/pkg/fedora/latest.spec b/pkg/fedora/latest.spec
index df78c789..084f1389 100644
--- a/pkg/fedora/latest.spec
+++ b/pkg/fedora/latest.spec
@@ -1,4 +1,4 @@
-%global basever 2.13.0
+%global basever 2.14.0
%global origrel 1
%global somajor 2
@@ -90,11 +90,5 @@ pushd repo/src
%{_libdir}/pkgconfig/Louvre.pc
%changelog
-* Sun Dec 08 2024 Eduardo Hopperdietzel - %{basever}-%{origrel}
-- Updated license to LGPLv2.1.
-- LTexture::write(Begin/Update/End): An alternative to LTexture::updateRect() that allows multiple texture updates without issuing an immediate internal synchronization.
-- LOutput::currentBufferAge: Retrieves the age of the current buffer according to the [EGL_EXT_buffer_age](https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_buffer_age.txt) extension specification.
-- Added damage tracking support.
-- LPainter::bindProgram() now fully synchronizes all uniforms and GL state, instead of just binding its GL program. This resolves issues encountered when integrating external shaders.
-- Replaced LScene index-based damage tracking with buffer age.
-- Updated SRM dependency to >= 0.11.0.
+* Mon Jan 27 2025 Eduardo Hopperdietzel - %{basever}-%{origrel}
+
diff --git a/src/lib/core/LCompositor.cpp b/src/lib/core/LCompositor.cpp
index e5f3ec96..6f0554b1 100644
--- a/src/lib/core/LCompositor.cpp
+++ b/src/lib/core/LCompositor.cpp
@@ -236,9 +236,6 @@ bool LCompositor::start()
goto fail;
}
- imp()->state = CompositorState::Initialized;
- initialized();
-
imp()->events[LEV_UNLOCK].events = EPOLLIN;
imp()->events[LEV_UNLOCK].data.fd = eventfd(0, EFD_NONBLOCK);
@@ -247,6 +244,8 @@ bool LCompositor::start()
compositor()->imp()->events[LEV_UNLOCK].data.fd,
&compositor()->imp()->events[LEV_UNLOCK]);
+ imp()->state = CompositorState::Initialized;
+ initialized();
return true;
fail:
@@ -340,9 +339,10 @@ Int32 LCompositor::processLoop(Int32 msTimeout)
imp()->destroyPendingRenderBuffers(nullptr);
imp()->handleDestroyedClients();
- imp()->handleOutputRepaintRequests();
}
+ imp()->handleOutputRepaintRequests();
+
if (state() == CompositorState::Uninitializing)
{
uninitialized();
diff --git a/src/lib/core/LOutput.cpp b/src/lib/core/LOutput.cpp
index 5d5c4530..86ca239e 100644
--- a/src/lib/core/LOutput.cpp
+++ b/src/lib/core/LOutput.cpp
@@ -351,6 +351,7 @@ Float32 LOutput::scale() const noexcept
void LOutput::repaint() noexcept
{
+ // Check LCompositor::processLoop() -> LCompositorPrivate::handleOutputRepaintRequests()
imp()->stateFlags.add(LOutputPrivate::PendingRepaint);
compositor()->imp()->unlockPoll();
}
diff --git a/src/lib/core/LOutput.h b/src/lib/core/LOutput.h
index fbd9d11c..09701897 100644
--- a/src/lib/core/LOutput.h
+++ b/src/lib/core/LOutput.h
@@ -1019,10 +1019,17 @@ class Louvre::LOutput : public LFactoryObject
virtual void availableGeometryChanged();
/**
- * @brief Selectively disables repaint calls.
+ * @brief Temporarily disables repaint calls for this output.
*
- * This method can be used to intercept repaint() calls and keep the last rendered frame.
- * If `false` is returned, the repaint() call is ignored, preventing paintGL() from being triggered.
+ * An output locks its rendering thread until repaint() is called. However, many objects and implementations
+ * within the compositor may automatically trigger repaints to reflect changes, making it difficult to
+ * prevent unwanted repaints.
+ *
+ * This method intercepts repaint() calls and preserves the last rendered frame. When `false` is returned,
+ * the repaint() calls are ignored, and paintGL() is not triggered.
+ *
+ * @note During initialization, uninitialization, or mode changes, the rendering thread is forcefully
+ * unlocked and the filter is ignored to prevent deadlocks.
*
* #### Default Implementation
*
diff --git a/src/lib/core/private/LCompositorPrivate.cpp b/src/lib/core/private/LCompositorPrivate.cpp
index 533b93d3..7b40694d 100644
--- a/src/lib/core/private/LCompositorPrivate.cpp
+++ b/src/lib/core/private/LCompositorPrivate.cpp
@@ -1069,6 +1069,15 @@ void LCompositor::LCompositorPrivate::handleOutputRepaintRequests() noexcept
for (LOutput *o : outputs)
{
+ if (!seat->enabled())
+ {
+ if (o->imp()->stateFlags.check(LOutput::LOutputPrivate::RepaintLocked))
+ {
+ o->imp()->stateFlags.remove(LOutput::LOutputPrivate::RepaintLocked);
+ o->imp()->repaintFilterMutex.unlock();
+ }
+ }
+
if (!o->imp()->stateFlags.check(LOutput::LOutputPrivate::PendingRepaint))
continue;
diff --git a/src/lib/core/private/LOutputPrivate.cpp b/src/lib/core/private/LOutputPrivate.cpp
index c3d856b0..d908957a 100644
--- a/src/lib/core/private/LOutputPrivate.cpp
+++ b/src/lib/core/private/LOutputPrivate.cpp
@@ -266,11 +266,17 @@ void LOutput::LOutputPrivate::backendPaintGL()
{
compositor()->imp()->lock();
+ // This means LOutput::repaintFilter() returned false
if (stateFlags.check(RepaintLocked))
{
+ // Unlock other threads (let the main loop update the RepaintLocked state)
compositor()->imp()->unlock();
+
+ // Wait until LOutput::repaintFilter() returns true
repaintFilterMutex.lock();
repaintFilterMutex.unlock();
+
+ // Continue rendering...
compositor()->imp()->lock();
compositor()->imp()->unlockPoll();
}
@@ -381,6 +387,8 @@ void LOutput::LOutputPrivate::backendPaintGL()
/* Destroy render buffers created from this thread and marked as destroyed by the user */
compositor()->imp()->destroyPendingRenderBuffers(&output->imp()->threadId);
+
+ /* Handle LOutput::repaint() calls from this thread */
compositor()->imp()->handleOutputRepaintRequests();
if (callLock)
diff --git a/src/lib/core/private/LSeatPrivate.cpp b/src/lib/core/private/LSeatPrivate.cpp
index a2857b62..0221ec1e 100644
--- a/src/lib/core/private/LSeatPrivate.cpp
+++ b/src/lib/core/private/LSeatPrivate.cpp
@@ -23,6 +23,15 @@ void LSeat::LSeatPrivate::seatEnabled(libseat *seat, void *data)
compositor()->imp()->unlock();
+ for (LOutput *o : compositor()->outputs())
+ {
+ if (o->imp()->stateFlags.check(LOutput::LOutputPrivate::RepaintLocked))
+ {
+ o->imp()->stateFlags.remove(LOutput::LOutputPrivate::RepaintLocked);
+ o->imp()->repaintFilterMutex.unlock();
+ }
+ }
+
if (compositor()->isGraphicBackendInitialized())
compositor()->imp()->graphicBackend->backendResume();
@@ -75,6 +84,15 @@ void LSeat::LSeatPrivate::seatDisabled(libseat *seat, void *data)
compositor()->imp()->unlock();
+ for (LOutput *o : compositor()->outputs())
+ {
+ if (o->imp()->stateFlags.check(LOutput::LOutputPrivate::RepaintLocked))
+ {
+ o->imp()->stateFlags.remove(LOutput::LOutputPrivate::RepaintLocked);
+ o->imp()->repaintFilterMutex.unlock();
+ }
+ }
+
if (compositor()->isGraphicBackendInitialized())
compositor()->imp()->graphicBackend->backendSuspend();