From 3d3fe5026a6a3e951ef56ad16a100b8d5ae84574 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 4 Dec 2015 17:59:42 +0000 Subject: Add choreographer API to the NDK. Change-Id: Icb8cffd3cd3bd06814466be72db3e26f6a62cbc6 --- libs/androidfw/DisplayEventDispatcher.cpp | 147 ++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 libs/androidfw/DisplayEventDispatcher.cpp (limited to 'libs/androidfw/DisplayEventDispatcher.cpp') diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp new file mode 100644 index 000000000000..99cd1732031c --- /dev/null +++ b/libs/androidfw/DisplayEventDispatcher.cpp @@ -0,0 +1,147 @@ +/* + * 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 +#include + +#include +#include +#include +#include + +#include + +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) : + mLooper(looper), 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; + int32_t vsyncDisplayId; + uint32_t vsyncCount; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", + this, ns2ms(static_cast(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; + int32_t vsyncDisplayId; + uint32_t vsyncCount; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + ALOGE("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d", + this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount); + mWaitingForVsync = false; + dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); + } + + return 1; // keep the callback +} + +bool DisplayEventDispatcher::processPendingEvents( + nsecs_t* outTimestamp, int32_t* outId, 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; + *outId = ev.header.id; + *outCount = ev.vsync.count; + break; + case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: + dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected); + 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; +} +} -- cgit v1.2.3-59-g8ed1b