M enabled_unittests => enabled_unittests +7 -0
@@ 233,6 233,13 @@ TESTS_LIST["catch2-PowerManager"]="
Power Manager CPU sentinels governor test;
"
#---------
+TESTS_LIST["catch2-render-cache-tests"]="
+ Render cache - default initialized;
+ Render cache - cache;
+ Render cache - cache and invalidate;
+ Render cache - exchange cached item;
+"
+#---------
TESTS_LIST["catch2-service-db"]="
DB_API;
Settings Messages;
M module-services/service-gui/CMakeLists.txt => module-services/service-gui/CMakeLists.txt +1 -0
@@ 5,6 5,7 @@ set(SOURCES
"${CMAKE_CURRENT_LIST_DIR}/ServiceGUI.cpp"
"${CMAKE_CURRENT_LIST_DIR}/WorkerGUI.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ContextPool.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/RenderCache.cpp"
"${CMAKE_CURRENT_LIST_DIR}/DrawCommandsQueue.cpp"
"${CMAKE_CURRENT_LIST_DIR}/SynchronizationMechanism.cpp"
"${CMAKE_CURRENT_LIST_DIR}/messages/DrawMessage.cpp"
A module-services/service-gui/RenderCache.cpp => module-services/service-gui/RenderCache.cpp +40 -0
@@ 0,0 1,40 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "RenderCache.hpp"
+
+namespace service::gui
+{
+ std::optional<RenderReference> RenderCache::getCachedRender() const
+ {
+ return cachedRender;
+ }
+
+ bool RenderCache::isRenderCached() const noexcept
+ {
+ return cachedRender.has_value();
+ }
+
+ void RenderCache::cache(RenderReference render)
+ {
+ if (isRenderCached()) {
+ exchange(render);
+ }
+ else {
+ cachedRender = render;
+ }
+ }
+
+ void RenderCache::exchange(RenderReference render)
+ {
+ if (cachedRender->refreshMode == ::gui::RefreshModes::GUI_REFRESH_DEEP) {
+ render.refreshMode = cachedRender->refreshMode;
+ }
+ cachedRender = render;
+ }
+
+ void RenderCache::invalidate()
+ {
+ cachedRender = std::nullopt;
+ }
+} // namespace service::gui
A module-services/service-gui/RenderCache.hpp => module-services/service-gui/RenderCache.hpp +31 -0
@@ 0,0 1,31 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <gui/Common.hpp>
+
+#include <optional>
+
+namespace service::gui
+{
+ struct RenderReference
+ {
+ int contextId;
+ ::gui::RefreshModes refreshMode;
+ };
+
+ class RenderCache
+ {
+ public:
+ std::optional<RenderReference> getCachedRender() const;
+ bool isRenderCached() const noexcept;
+ void cache(RenderReference render);
+ void invalidate();
+
+ private:
+ void exchange(RenderReference render);
+
+ std::optional<RenderReference> cachedRender;
+ };
+} // namespace service::gui
M module-services/service-gui/ServiceGUI.cpp => module-services/service-gui/ServiceGUI.cpp +18 -17
@@ 33,6 33,14 @@ namespace service::gui
constexpr std::chrono::milliseconds BSPEinkBusyTimeout{3000}; ///< sync with \ref BSP_EinkBusyTimeout
constexpr std::chrono::milliseconds RTOSMessageRoundtripTimeout{1000};
constexpr std::chrono::milliseconds ContextReleaseTimeout{BSPEinkBusyTimeout + RTOSMessageRoundtripTimeout};
+
+ ::gui::RefreshModes getMaxRefreshMode(::gui::RefreshModes lhs, ::gui::RefreshModes rhs) noexcept
+ {
+ if (lhs == ::gui::RefreshModes::GUI_REFRESH_DEEP) {
+ return lhs;
+ }
+ return rhs;
+ }
} // namespace
ServiceGUI::ServiceGUI(const std::string &name, std::string parent)
@@ 184,14 192,17 @@ namespace service::gui
{
auto finishedMsg = static_cast<service::gui::RenderingFinished *>(message);
const auto contextId = finishedMsg->getContextId();
- const auto refreshMode = finishedMsg->getRefreshMode();
+ auto refreshMode = finishedMsg->getRefreshMode();
if (isInState(State::Idle)) {
+ if (cache.isRenderCached()) {
+ refreshMode = getMaxRefreshMode(cache.getCachedRender()->refreshMode, refreshMode);
+ cache.invalidate();
+ }
const auto context = contextPool->peekContext(contextId);
sendOnDisplay(context, contextId, refreshMode);
- invalidateCache();
}
else {
- cacheRender(contextId, refreshMode);
+ cache.cache({contextId, refreshMode});
contextPool->returnContext(contextId);
}
return sys::MessageNone{};
@@ 218,16 229,6 @@ namespace service::gui
contextReleaseTimer.start();
}
- void ServiceGUI::cacheRender(int contextId, ::gui::RefreshModes refreshMode)
- {
- cachedRender = CachedRender{contextId, refreshMode};
- }
-
- void ServiceGUI::invalidateCache()
- {
- cachedRender = std::nullopt;
- }
-
sys::MessagePointer ServiceGUI::handleEinkInitialized(sys::Message *message)
{
const auto msg = static_cast<service::gui::EinkInitialized *>(message);
@@ 258,7 259,7 @@ namespace service::gui
bool ServiceGUI::isNextFrameReady() const noexcept
{
- return cachedRender.has_value();
+ return cache.isRenderCached();
}
bool ServiceGUI::isAnyFrameBeingRenderedOrDisplayed() const noexcept
@@ 268,11 269,11 @@ namespace service::gui
void ServiceGUI::trySendNextFrame()
{
- const auto contextId = cachedRender->contextId;
+ const auto contextId = cache.getCachedRender()->contextId;
if (const auto context = contextPool->borrowContext(contextId); context != nullptr) {
- sendOnDisplay(context, contextId, cachedRender->refreshMode);
+ sendOnDisplay(context, contextId, cache.getCachedRender()->refreshMode);
}
- invalidateCache();
+ cache.invalidate();
}
void ServiceGUI::setState(State state) noexcept
M module-services/service-gui/ServiceGUI.hpp => module-services/service-gui/ServiceGUI.hpp +2 -9
@@ 16,6 16,7 @@
#include "ContextPool.hpp"
#include "DrawCommandsQueue.hpp"
#include "Common.hpp"
+#include "RenderCache.hpp"
#include <cstdint>
#include <memory>
@@ 46,11 47,6 @@ namespace service::gui
sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override;
private:
- struct CachedRender
- {
- int contextId;
- ::gui::RefreshModes refreshMode;
- };
enum class State
{
NotInitialised,
@@ 62,9 58,6 @@ namespace service::gui
static void initAssetManagers();
void registerMessageHandlers();
- void cacheRender(int contextId, ::gui::RefreshModes refreshMode);
- void invalidateCache();
-
void prepareDisplayEarly(::gui::RefreshModes refreshMode);
void notifyRenderer(std::list<std::unique_ptr<::gui::DrawCommand>> &&commands, ::gui::RefreshModes refreshMode);
void notifyRenderColorSchemeChange(::gui::ColorScheme &&scheme);
@@ 88,7 81,7 @@ namespace service::gui
std::unique_ptr<WorkerGUI> worker;
std::unique_ptr<DrawCommandsQueue> commandsQueue;
std::unique_ptr<::gui::ColorScheme> colorSchemeUpdate;
- std::optional<CachedRender> cachedRender;
+ RenderCache cache;
sys::TimerHandle contextReleaseTimer;
State currentState;
bool lastRenderScheduled;
M module-services/service-gui/tests/CMakeLists.txt => module-services/service-gui/tests/CMakeLists.txt +10 -0
@@ 19,3 19,13 @@ add_catch2_executable(
LIBS
service-gui
)
+
+add_catch2_executable(
+ NAME
+ render-cache-tests
+ SRCS
+ tests-main.cpp
+ test-RenderCache.cpp
+ LIBS
+ service-gui
+)
A module-services/service-gui/tests/test-RenderCache.cpp => module-services/service-gui/tests/test-RenderCache.cpp +48 -0
@@ 0,0 1,48 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <catch2/catch.hpp>
+
+#include "RenderCache.hpp"
+
+using namespace service::gui;
+
+TEST_CASE("Render cache - default initialized")
+{
+ RenderCache cache;
+
+ REQUIRE(!cache.isRenderCached());
+}
+
+TEST_CASE("Render cache - cache")
+{
+ RenderCache cache;
+
+ cache.cache({1, ::gui::RefreshModes::GUI_REFRESH_DEEP});
+
+ REQUIRE(cache.isRenderCached());
+ REQUIRE(cache.getCachedRender()->contextId == 1);
+ REQUIRE(cache.getCachedRender()->refreshMode == ::gui::RefreshModes::GUI_REFRESH_DEEP);
+}
+
+TEST_CASE("Render cache - cache and invalidate")
+{
+ RenderCache cache;
+
+ cache.cache({1, ::gui::RefreshModes::GUI_REFRESH_DEEP});
+ cache.invalidate();
+
+ REQUIRE(!cache.isRenderCached());
+}
+
+TEST_CASE("Render cache - exchange cached item")
+{
+ RenderCache cache;
+
+ cache.cache({1, ::gui::RefreshModes::GUI_REFRESH_DEEP});
+ cache.cache({2, ::gui::RefreshModes::GUI_REFRESH_FAST});
+
+ REQUIRE(cache.isRenderCached());
+ REQUIRE(cache.getCachedRender()->contextId == 2);
+ REQUIRE(cache.getCachedRender()->refreshMode == ::gui::RefreshModes::GUI_REFRESH_DEEP);
+}