diff options
author | 2019-10-28 16:44:36 -0700 | |
---|---|---|
committer | 2019-11-25 13:50:50 -0800 | |
commit | 77a5387b22d9aed504ac5abe021999dbbecb4b7e (patch) | |
tree | 5afdb064d555d0b1991db88993a4b99d76f35c78 /libs/gui/DisplayEventDispatcher.cpp | |
parent | 2ffb68277d130f8310682a1298d2488e712c092c (diff) |
[DisplayEventDispatcher] Move DisplayEventDispatcher into libgui.
Original source file was at frameworks/base/libs/androidfw.
For now, libgui will be its new home so that the graphics module can
depend on libandroidfw without pulling in libgui.
Bug: 142760698
Test: builds
Change-Id: Iea51e24ffb11a6ad79ad91a9e887f5e326705f1b
Diffstat (limited to 'libs/gui/DisplayEventDispatcher.cpp')
-rw-r--r-- | libs/gui/DisplayEventDispatcher.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp new file mode 100644 index 0000000000..54f383e915 --- /dev/null +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 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. + */ + +#define LOG_TAG "DisplayEventDispatcher" + +#include <cinttypes> +#include <cstdint> + +#include <gui/DisplayEventDispatcher.h> +#include <gui/DisplayEventReceiver.h> +#include <utils/Log.h> +#include <utils/Looper.h> + +#include <utils/Timers.h> + +namespace android { + +// Number of events to read at a time from the DisplayEventDispatcher pipe. +// The value should be large enough that we can quickly drain the pipe +// using just a few large reads. +static const size_t EVENT_BUFFER_SIZE = 100; + +DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper, + ISurfaceComposer::VsyncSource vsyncSource, + ISurfaceComposer::ConfigChanged configChanged) + : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) { + ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); +} + +status_t DisplayEventDispatcher::initialize() { + status_t result = mReceiver.initCheck(); + if (result) { + ALOGW("Failed to initialize display event receiver, status=%d", result); + return result; + } + + int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL); + if (rc < 0) { + return UNKNOWN_ERROR; + } + return OK; +} + +void DisplayEventDispatcher::dispose() { + ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this); + + if (!mReceiver.initCheck()) { + mLooper->removeFd(mReceiver.getFd()); + } +} + +status_t DisplayEventDispatcher::scheduleVsync() { + if (!mWaitingForVsync) { + ALOGV("dispatcher %p ~ Scheduling vsync.", this); + + // Drain all pending events. + nsecs_t vsyncTimestamp; + PhysicalDisplayId vsyncDisplayId; + uint32_t vsyncCount; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this, + ns2ms(static_cast<nsecs_t>(vsyncTimestamp))); + } + + status_t status = mReceiver.requestNextVsync(); + if (status) { + ALOGW("Failed to request next vsync, status=%d", status); + return status; + } + + mWaitingForVsync = true; + } + return OK; +} + +int DisplayEventDispatcher::handleEvent(int, int events, void*) { + if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { + ALOGE("Display event receiver pipe was closed or an error occurred. " + "events=0x%x", + events); + return 0; // remove the callback + } + + if (!(events & Looper::EVENT_INPUT)) { + ALOGW("Received spurious callback for unhandled poll event. " + "events=0x%x", + events); + return 1; // keep the callback + } + + // Drain all pending events, keep the last vsync. + nsecs_t vsyncTimestamp; + PhysicalDisplayId vsyncDisplayId; + uint32_t vsyncCount; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 + ", displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d", + this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount); + mWaitingForVsync = false; + dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); + } + + return 1; // keep the callback +} + +bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, + PhysicalDisplayId* outDisplayId, + uint32_t* outCount) { + bool gotVsync = false; + DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; + ssize_t n; + while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { + ALOGV("dispatcher %p ~ Read %d events.", this, int(n)); + for (ssize_t i = 0; i < n; i++) { + const DisplayEventReceiver::Event& ev = buf[i]; + switch (ev.header.type) { + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: + // Later vsync events will just overwrite the info from earlier + // ones. That's fine, we only care about the most recent. + gotVsync = true; + *outTimestamp = ev.header.timestamp; + *outDisplayId = ev.header.displayId; + *outCount = ev.vsync.count; + break; + case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: + dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); + break; + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, + ev.config.configId); + break; + default: + ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type); + break; + } + } + } + if (n < 0) { + ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n)); + } + return gotVsync; +} +} // namespace android |