Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <gtest/gtest.h>
     18 #include <thread>
     19 
     20 #include <binder/ProcessState.h>
     21 #include <gui/DisplayEventReceiver.h>
     22 #include <gui/IRegionSamplingListener.h>
     23 #include <gui/ISurfaceComposer.h>
     24 #include <gui/Surface.h>
     25 #include <gui/SurfaceComposerClient.h>
     26 #include <private/gui/ComposerService.h>
     27 #include <utils/Looper.h>
     28 
     29 using namespace std::chrono_literals;
     30 
     31 namespace android::test {
     32 
     33 struct ChoreographerSync {
     34     ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
     35     ~ChoreographerSync() = default;
     36 
     37     void notify() const {
     38         std::unique_lock<decltype(mutex_)> lk(mutex_);
     39 
     40         auto check_event = [](auto const& ev) -> bool {
     41             return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
     42         };
     43         DisplayEventReceiver::Event ev_;
     44         int evs = receiver_.getEvents(&ev_, 1);
     45         auto vsync_event_found = check_event(ev_);
     46         while (evs) {
     47             evs = receiver_.getEvents(&ev_, 1);
     48             vsync_event_found |= check_event(ev_);
     49         }
     50 
     51         if (vsync_event_found) {
     52             notification_arrived_ = true;
     53             cv_.notify_all();
     54         }
     55     }
     56 
     57     void wait_vsync_notify() const {
     58         std::unique_lock<decltype(mutex_)> lk(mutex_);
     59         cv_.wait(lk, [this] { return notification_arrived_; });
     60         notification_arrived_ = false;
     61     }
     62 
     63 private:
     64     ChoreographerSync(ChoreographerSync const&) = delete;
     65     ChoreographerSync& operator=(ChoreographerSync const&) = delete;
     66 
     67     std::mutex mutable mutex_;
     68     std::condition_variable mutable cv_;
     69     bool mutable notification_arrived_ = false;
     70     DisplayEventReceiver& receiver_;
     71 };
     72 
     73 struct ChoreographerSim {
     74     static std::unique_ptr<ChoreographerSim> make() {
     75         auto receiver = std::make_unique<DisplayEventReceiver>();
     76         if (!receiver || receiver->initCheck() == NO_INIT) {
     77             ALOGE("No display reciever");
     78             return nullptr;
     79         }
     80         return std::unique_ptr<ChoreographerSim>(new ChoreographerSim(std::move(receiver)));
     81     }
     82 
     83     ~ChoreographerSim() {
     84         poll_ = false;
     85         looper->wake();
     86         choreographer_thread_.join();
     87     }
     88 
     89     void request_render_wait(std::function<void()> const& render_fn) {
     90         display_event_receiver_->requestNextVsync();
     91         choreographer_.wait_vsync_notify();
     92         render_fn();
     93 
     94         // Purpose is to make sure that the content is latched by the time we sample.
     95         // Waiting one vsync after queueing could still race with vsync, so wait for two, after
     96         // which the content is pretty reliably on screen.
     97         display_event_receiver_->requestNextVsync();
     98         choreographer_.wait_vsync_notify();
     99         display_event_receiver_->requestNextVsync();
    100         choreographer_.wait_vsync_notify();
    101     }
    102 
    103 private:
    104     ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
    105           : display_event_receiver_{std::move(receiver)},
    106             choreographer_{*display_event_receiver_},
    107             looper{new Looper(false)} {
    108         choreographer_thread_ = std::thread([this] {
    109             auto vsync_notify_fd = display_event_receiver_->getFd();
    110             looper->addFd(vsync_notify_fd, 0, Looper::EVENT_INPUT,
    111                           [](int /*fd*/, int /*events*/, void* data) -> int {
    112                               if (!data) return 0;
    113                               reinterpret_cast<ChoreographerSync*>(data)->notify();
    114                               return 1;
    115                           },
    116                           const_cast<void*>(reinterpret_cast<void const*>(&choreographer_)));
    117 
    118             while (poll_) {
    119                 auto const poll_interval =
    120                         std::chrono::duration_cast<std::chrono::milliseconds>(1s).count();
    121                 auto rc = looper->pollOnce(poll_interval);
    122                 if ((rc != Looper::POLL_CALLBACK) && (rc != Looper::POLL_WAKE))
    123                     ALOGW("Vsync Looper returned: %i\n", rc);
    124             }
    125         });
    126     }
    127 
    128     ChoreographerSim(ChoreographerSim const&) = delete;
    129     ChoreographerSim& operator=(ChoreographerSim const&) = delete;
    130 
    131     std::unique_ptr<DisplayEventReceiver> const display_event_receiver_;
    132     ChoreographerSync const choreographer_;
    133     sp<Looper> looper;
    134     std::thread choreographer_thread_;
    135     std::atomic<bool> poll_{true};
    136 };
    137 
    138 struct Listener : BnRegionSamplingListener {
    139     void onSampleCollected(float medianLuma) override {
    140         std::unique_lock<decltype(mutex)> lk(mutex);
    141         received = true;
    142         mLuma = medianLuma;
    143         cv.notify_all();
    144     };
    145     bool wait_event(std::chrono::milliseconds timeout) {
    146         std::unique_lock<decltype(mutex)> lk(mutex);
    147         return cv.wait_for(lk, timeout, [this] { return received; });
    148     }
    149 
    150     float luma() {
    151         std::unique_lock<decltype(mutex)> lk(mutex);
    152         return mLuma;
    153     }
    154 
    155     void reset() {
    156         std::unique_lock<decltype(mutex)> lk(mutex);
    157         received = false;
    158     }
    159 
    160 private:
    161     std::condition_variable cv;
    162     std::mutex mutex;
    163     bool received = false;
    164     float mLuma = -0.0f;
    165 };
    166 
    167 // Hoisted to TestSuite setup to avoid flake in test (b/124675919)
    168 std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
    169 
    170 struct RegionSamplingTest : ::testing::Test {
    171 protected:
    172     RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
    173 
    174     static void SetUpTestSuite() {
    175         gChoreographerSim = ChoreographerSim::make();
    176         ASSERT_NE(gChoreographerSim, nullptr);
    177     }
    178 
    179     void SetUp() override {
    180         mSurfaceComposerClient = new SurfaceComposerClient;
    181         ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
    182 
    183         mBackgroundLayer =
    184                 mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
    185                                                       0, PIXEL_FORMAT_RGBA_8888,
    186                                                       ISurfaceComposerClient::eFXSurfaceColor);
    187         uint32_t layerPositionBottom = 0x7E000000;
    188         SurfaceComposerClient::Transaction{}
    189                 .setLayer(mBackgroundLayer, layerPositionBottom)
    190                 .setPosition(mBackgroundLayer, 100, 100)
    191                 .setColor(mBackgroundLayer, half3{0.5, 0.5, 0.5})
    192                 .show(mBackgroundLayer)
    193                 .apply();
    194 
    195         mContentLayer = mSurfaceComposerClient->createSurface(String8("Content RegionSamplingTest"),
    196                                                               300, 300, PIXEL_FORMAT_RGBA_8888, 0);
    197 
    198         SurfaceComposerClient::Transaction{}
    199                 .setLayer(mContentLayer, layerPositionBottom + 1)
    200                 .setPosition(mContentLayer, 100, 100)
    201                 .setColor(mContentLayer, half3{0.5, 0.5, 0.5})
    202                 .show(mContentLayer)
    203                 .apply();
    204 
    205         mTopLayer = mSurfaceComposerClient->createSurface(String8("TopLayer RegionSamplingTest"), 0,
    206                                                           0, PIXEL_FORMAT_RGBA_8888, 0);
    207         SurfaceComposerClient::Transaction{}
    208                 .setLayer(mTopLayer, layerPositionBottom + 2)
    209                 .setPosition(mTopLayer, 0, 0)
    210                 .show(mBackgroundLayer)
    211                 .apply();
    212     }
    213 
    214     void fill_render(uint32_t rgba_value) {
    215         auto surface = mContentLayer->getSurface();
    216         ANativeWindow_Buffer outBuffer;
    217         status_t status = surface->lock(&outBuffer, NULL);
    218         ASSERT_EQ(status, android::OK);
    219         auto b = reinterpret_cast<uint32_t*>(outBuffer.bits);
    220         for (auto i = 0; i < outBuffer.height; i++) {
    221             for (auto j = 0; j < outBuffer.width; j++) {
    222                 b[j] = rgba_value;
    223             }
    224             b += outBuffer.stride;
    225         }
    226 
    227         gChoreographerSim->request_render_wait([&surface] { surface->unlockAndPost(); });
    228     }
    229 
    230     sp<SurfaceComposerClient> mSurfaceComposerClient;
    231     sp<SurfaceControl> mBackgroundLayer;
    232     sp<SurfaceControl> mContentLayer;
    233     sp<SurfaceControl> mTopLayer;
    234 
    235     uint32_t const rgba_green = 0xFF00FF00;
    236     float const luma_green = 0.7152;
    237     uint32_t const rgba_blue = 0xFFFF0000;
    238     float const luma_blue = 0.0722;
    239     float const error_margin = 0.01;
    240     float const luma_gray = 0.50;
    241 };
    242 
    243 TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
    244     fill_render(rgba_green);
    245 
    246     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
    247     sp<Listener> listener = new Listener();
    248     const Rect sampleArea{100, 100, 200, 200};
    249     composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
    250 
    251     EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
    252     EXPECT_NEAR(listener->luma(), luma_green, error_margin);
    253 
    254     composer->removeRegionSamplingListener(listener);
    255 }
    256 
    257 TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
    258     fill_render(rgba_green);
    259 
    260     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
    261     sp<Listener> listener = new Listener();
    262     const Rect sampleArea{100, 100, 200, 200};
    263     composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
    264 
    265     EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
    266     EXPECT_NEAR(listener->luma(), luma_green, error_margin);
    267 
    268     listener->reset();
    269 
    270     fill_render(rgba_blue);
    271     EXPECT_TRUE(listener->wait_event(300ms))
    272             << "timed out waiting for 2nd luma event to be received";
    273     EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
    274 
    275     composer->removeRegionSamplingListener(listener);
    276 }
    277 
    278 TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
    279     fill_render(rgba_green);
    280     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
    281     sp<Listener> greenListener = new Listener();
    282     const Rect greenSampleArea{100, 100, 200, 200};
    283     composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
    284 
    285     sp<Listener> grayListener = new Listener();
    286     const Rect graySampleArea{500, 100, 600, 200};
    287     composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
    288 
    289     EXPECT_TRUE(grayListener->wait_event(300ms))
    290             << "timed out waiting for luma event to be received";
    291     EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
    292     EXPECT_TRUE(greenListener->wait_event(300ms))
    293             << "timed out waiting for luma event to be received";
    294     EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
    295 
    296     composer->removeRegionSamplingListener(greenListener);
    297     composer->removeRegionSamplingListener(grayListener);
    298 }
    299 
    300 } // namespace android::test
    301