Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 910c0aa1 authored by Ana Krulec's avatar Ana Krulec Committed by Android (Google) Code Review
Browse files

Merge "SF: Create a cicular buffer structure to store layer information."

parents 8d1e1075 61f86db9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ filegroup {
        "Scheduler/DispSyncSource.cpp",
        "Scheduler/EventControlThread.cpp",
        "Scheduler/EventThread.cpp",
        "Scheduler/LayerHistory.cpp",
        "Scheduler/MessageQueue.cpp",
        "Scheduler/Scheduler.cpp",
        "StartPropertySetThread.cpp",
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "LayerHistory.h"

#include <cinttypes>
#include <cstdint>
#include <numeric>
#include <string>
#include <unordered_map>

#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/Trace.h>

namespace android {

LayerHistory::LayerHistory() {}

LayerHistory::~LayerHistory() = default;

void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) {
    mElements[mCounter].insert(std::make_pair(layerName, presentTime));
}

void LayerHistory::incrementCounter() {
    mCounter++;
    mCounter = mCounter % ARRAY_SIZE;
    mElements[mCounter].clear();
}

const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const {
    return mElements.at(index);
}

} // namespace android
 No newline at end of file
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <array>
#include <cinttypes>
#include <cstdint>
#include <numeric>
#include <string>
#include <unordered_map>

#include <utils/Timers.h>

namespace android {

/*
 * This class represents a circular buffer in which we keep layer history for
 * the past ARRAY_SIZE frames. Each time, a signal for new frame comes, the counter
 * gets incremented and includes all the layers that are requested to draw in that
 * frame.
 *
 * Once the buffer reaches the end of the array, it starts overriding the elements
 * at the beginning of the array.
 */
class LayerHistory {
public:
    LayerHistory();
    ~LayerHistory();

    // Method for inserting layers and their requested present time into the ring buffer.
    // The elements are going to be inserted into an unordered_map at the position of
    // mCounter.
    void insert(const std::string layerName, nsecs_t presentTime);
    // Method for incrementing the current slot in the ring buffer. It also clears the
    // unordered_map, if it was created previously.
    void incrementCounter();
    // Returns unordered_map at the given at index.
    const std::unordered_map<std::string, nsecs_t>& get(size_t index) const;

private:
    size_t mCounter = 0;
    static constexpr size_t ARRAY_SIZE = 30;
    std::array<std::unordered_map<std::string, nsecs_t>, ARRAY_SIZE> mElements;
};

} // namespace android
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ cc_test {
        "DisplayTransactionTest.cpp",
        "EventControlThreadTest.cpp",
        "EventThreadTest.cpp",
        "LayerHistoryTest.cpp",
        "SchedulerTest.cpp",
        "mock/DisplayHardware/MockComposer.cpp",
        "mock/DisplayHardware/MockDisplaySurface.cpp",
+144 −0
Original line number Diff line number Diff line
#undef LOG_TAG
#define LOG_TAG "LayerHistoryUnittests"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <log/log.h>

#include <mutex>

#include "Scheduler/LayerHistory.h"

using testing::_;
using testing::Return;

namespace android {

class LayerHistoryTest : public testing::Test {
public:
    LayerHistoryTest();
    ~LayerHistoryTest() override;

protected:
    std::unique_ptr<LayerHistory> mLayerHistory;
};

LayerHistoryTest::LayerHistoryTest() {
    mLayerHistory = std::make_unique<LayerHistory>();
}
LayerHistoryTest::~LayerHistoryTest() {}

namespace {
TEST_F(LayerHistoryTest, simpleInsertAndGet) {
    mLayerHistory->insert("TestLayer", 0);

    const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0);
    EXPECT_EQ(1, testMap.size());
    auto element = testMap.find("TestLayer");
    EXPECT_EQ("TestLayer", element->first);
    EXPECT_EQ(0, element->second);

    // Testing accessing object at an empty container will return an empty map.
    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1);
    EXPECT_EQ(0, emptyMap.size());
}

TEST_F(LayerHistoryTest, multipleInserts) {
    mLayerHistory->insert("TestLayer0", 0);
    mLayerHistory->insert("TestLayer1", 1);
    mLayerHistory->insert("TestLayer2", 2);
    mLayerHistory->insert("TestLayer3", 3);

    const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0);
    // Because the counter was not incremented, all elements were inserted into the first
    // container.
    EXPECT_EQ(4, testMap.size());
    auto element = testMap.find("TestLayer0");
    EXPECT_EQ("TestLayer0", element->first);
    EXPECT_EQ(0, element->second);

    element = testMap.find("TestLayer1");
    EXPECT_EQ("TestLayer1", element->first);
    EXPECT_EQ(1, element->second);

    element = testMap.find("TestLayer2");
    EXPECT_EQ("TestLayer2", element->first);
    EXPECT_EQ(2, element->second);

    element = testMap.find("TestLayer3");
    EXPECT_EQ("TestLayer3", element->first);
    EXPECT_EQ(3, element->second);

    // Testing accessing object at an empty container will return an empty map.
    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1);
    EXPECT_EQ(0, emptyMap.size());
}

TEST_F(LayerHistoryTest, incrementingCounter) {
    mLayerHistory->insert("TestLayer0", 0);
    mLayerHistory->incrementCounter();
    mLayerHistory->insert("TestLayer1", 1);
    mLayerHistory->insert("TestLayer2", 2);
    mLayerHistory->incrementCounter();
    mLayerHistory->insert("TestLayer3", 3);

    // Because the counter was incremented, the elements were inserted into different
    // containers.
    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
    EXPECT_EQ(1, testMap1.size());
    auto element = testMap1.find("TestLayer0");
    EXPECT_EQ("TestLayer0", element->first);
    EXPECT_EQ(0, element->second);

    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1);
    EXPECT_EQ(2, testMap2.size());
    element = testMap2.find("TestLayer1");
    EXPECT_EQ("TestLayer1", element->first);
    EXPECT_EQ(1, element->second);
    element = testMap2.find("TestLayer2");
    EXPECT_EQ("TestLayer2", element->first);
    EXPECT_EQ(2, element->second);

    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2);
    EXPECT_EQ(1, testMap3.size());
    element = testMap3.find("TestLayer3");
    EXPECT_EQ("TestLayer3", element->first);
    EXPECT_EQ(3, element->second);

    // Testing accessing object at an empty container will return an empty map.
    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3);
    EXPECT_EQ(0, emptyMap.size());
}

TEST_F(LayerHistoryTest, clearTheMap) {
    mLayerHistory->insert("TestLayer0", 0);
    mLayerHistory->incrementCounter();

    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
    EXPECT_EQ(1, testMap1.size());
    auto element = testMap1.find("TestLayer0");
    EXPECT_EQ("TestLayer0", element->first);
    EXPECT_EQ(0, element->second);

    // The array currently contains 30 elements.
    for (int i = 1; i < 30; ++i) {
        mLayerHistory->insert("TestLayer0", i);
        mLayerHistory->incrementCounter();
    }
    // Expect the map to be cleared.
    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(0);
    EXPECT_EQ(0, testMap2.size());

    mLayerHistory->insert("TestLayer30", 30);
    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(0);
    element = testMap3.find("TestLayer30");
    EXPECT_EQ("TestLayer30", element->first);
    EXPECT_EQ(30, element->second);
    // The original element in this location does not exist anymore.
    element = testMap3.find("TestLayer0");
    EXPECT_EQ(testMap3.end(), element);
}

} // namespace
} // namespace android
 No newline at end of file