~aleteoryx/muditaos

90c4a0a39f0f413b75b54cb856697169a63502fc — Piotr Tański 4 years ago 97833e2
[EGD-6529] Fixed issues with gray colors

The issue occurred on multiple refreshes in the short period of time.
Sometimes, fast refresh was performed instead of the cached deep one.
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);
}