1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "DisplayEventDispatcher"
18*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker #include <cinttypes>
21*38e8c45fSAndroid Build Coastguard Worker #include <cstdint>
22*38e8c45fSAndroid Build Coastguard Worker
23*38e8c45fSAndroid Build Coastguard Worker #include <gui/DisplayEventDispatcher.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <gui/DisplayEventReceiver.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <utils/Looper.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <utils/Trace.h>
29*38e8c45fSAndroid Build Coastguard Worker
30*38e8c45fSAndroid Build Coastguard Worker #include <com_android_graphics_libgui_flags.h>
31*38e8c45fSAndroid Build Coastguard Worker
32*38e8c45fSAndroid Build Coastguard Worker namespace android {
33*38e8c45fSAndroid Build Coastguard Worker using namespace com::android::graphics::libgui;
34*38e8c45fSAndroid Build Coastguard Worker
35*38e8c45fSAndroid Build Coastguard Worker // Number of events to read at a time from the DisplayEventDispatcher pipe.
36*38e8c45fSAndroid Build Coastguard Worker // The value should be large enough that we can quickly drain the pipe
37*38e8c45fSAndroid Build Coastguard Worker // using just a few large reads.
38*38e8c45fSAndroid Build Coastguard Worker static const size_t EVENT_BUFFER_SIZE = 100;
39*38e8c45fSAndroid Build Coastguard Worker
40*38e8c45fSAndroid Build Coastguard Worker static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
41*38e8c45fSAndroid Build Coastguard Worker
DisplayEventDispatcher(const sp<Looper> & looper,gui::ISurfaceComposer::VsyncSource vsyncSource,EventRegistrationFlags eventRegistration,const sp<IBinder> & layerHandle)42*38e8c45fSAndroid Build Coastguard Worker DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
43*38e8c45fSAndroid Build Coastguard Worker gui::ISurfaceComposer::VsyncSource vsyncSource,
44*38e8c45fSAndroid Build Coastguard Worker EventRegistrationFlags eventRegistration,
45*38e8c45fSAndroid Build Coastguard Worker const sp<IBinder>& layerHandle)
46*38e8c45fSAndroid Build Coastguard Worker : mLooper(looper),
47*38e8c45fSAndroid Build Coastguard Worker mReceiver(vsyncSource, eventRegistration, layerHandle),
48*38e8c45fSAndroid Build Coastguard Worker mWaitingForVsync(false),
49*38e8c45fSAndroid Build Coastguard Worker mLastVsyncCount(0),
50*38e8c45fSAndroid Build Coastguard Worker mLastScheduleVsyncTime(0) {
51*38e8c45fSAndroid Build Coastguard Worker ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
52*38e8c45fSAndroid Build Coastguard Worker }
53*38e8c45fSAndroid Build Coastguard Worker
initialize()54*38e8c45fSAndroid Build Coastguard Worker status_t DisplayEventDispatcher::initialize() {
55*38e8c45fSAndroid Build Coastguard Worker status_t result = mReceiver.initCheck();
56*38e8c45fSAndroid Build Coastguard Worker if (result) {
57*38e8c45fSAndroid Build Coastguard Worker ALOGW("Failed to initialize display event receiver, status=%d", result);
58*38e8c45fSAndroid Build Coastguard Worker return result;
59*38e8c45fSAndroid Build Coastguard Worker }
60*38e8c45fSAndroid Build Coastguard Worker
61*38e8c45fSAndroid Build Coastguard Worker if (mLooper != nullptr) {
62*38e8c45fSAndroid Build Coastguard Worker int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
63*38e8c45fSAndroid Build Coastguard Worker if (rc < 0) {
64*38e8c45fSAndroid Build Coastguard Worker return UNKNOWN_ERROR;
65*38e8c45fSAndroid Build Coastguard Worker }
66*38e8c45fSAndroid Build Coastguard Worker }
67*38e8c45fSAndroid Build Coastguard Worker
68*38e8c45fSAndroid Build Coastguard Worker return OK;
69*38e8c45fSAndroid Build Coastguard Worker }
70*38e8c45fSAndroid Build Coastguard Worker
dispose()71*38e8c45fSAndroid Build Coastguard Worker void DisplayEventDispatcher::dispose() {
72*38e8c45fSAndroid Build Coastguard Worker ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this);
73*38e8c45fSAndroid Build Coastguard Worker
74*38e8c45fSAndroid Build Coastguard Worker if (!mReceiver.initCheck() && mLooper != nullptr) {
75*38e8c45fSAndroid Build Coastguard Worker mLooper->removeFd(mReceiver.getFd());
76*38e8c45fSAndroid Build Coastguard Worker }
77*38e8c45fSAndroid Build Coastguard Worker }
78*38e8c45fSAndroid Build Coastguard Worker
scheduleVsync()79*38e8c45fSAndroid Build Coastguard Worker status_t DisplayEventDispatcher::scheduleVsync() {
80*38e8c45fSAndroid Build Coastguard Worker if (!mWaitingForVsync) {
81*38e8c45fSAndroid Build Coastguard Worker ALOGV("dispatcher %p ~ Scheduling vsync.", this);
82*38e8c45fSAndroid Build Coastguard Worker
83*38e8c45fSAndroid Build Coastguard Worker // Drain all pending events.
84*38e8c45fSAndroid Build Coastguard Worker nsecs_t vsyncTimestamp;
85*38e8c45fSAndroid Build Coastguard Worker PhysicalDisplayId vsyncDisplayId;
86*38e8c45fSAndroid Build Coastguard Worker uint32_t vsyncCount;
87*38e8c45fSAndroid Build Coastguard Worker VsyncEventData vsyncEventData;
88*38e8c45fSAndroid Build Coastguard Worker if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
89*38e8c45fSAndroid Build Coastguard Worker ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
90*38e8c45fSAndroid Build Coastguard Worker ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
91*38e8c45fSAndroid Build Coastguard Worker }
92*38e8c45fSAndroid Build Coastguard Worker
93*38e8c45fSAndroid Build Coastguard Worker status_t status = mReceiver.requestNextVsync();
94*38e8c45fSAndroid Build Coastguard Worker if (status) {
95*38e8c45fSAndroid Build Coastguard Worker ALOGW("Failed to request next vsync, status=%d", status);
96*38e8c45fSAndroid Build Coastguard Worker return status;
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker
99*38e8c45fSAndroid Build Coastguard Worker mWaitingForVsync = true;
100*38e8c45fSAndroid Build Coastguard Worker mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
101*38e8c45fSAndroid Build Coastguard Worker }
102*38e8c45fSAndroid Build Coastguard Worker return OK;
103*38e8c45fSAndroid Build Coastguard Worker }
104*38e8c45fSAndroid Build Coastguard Worker
injectEvent(const DisplayEventReceiver::Event & event)105*38e8c45fSAndroid Build Coastguard Worker void DisplayEventDispatcher::injectEvent(const DisplayEventReceiver::Event& event) {
106*38e8c45fSAndroid Build Coastguard Worker mReceiver.sendEvents(&event, 1);
107*38e8c45fSAndroid Build Coastguard Worker }
108*38e8c45fSAndroid Build Coastguard Worker
getFd() const109*38e8c45fSAndroid Build Coastguard Worker int DisplayEventDispatcher::getFd() const {
110*38e8c45fSAndroid Build Coastguard Worker return mReceiver.getFd();
111*38e8c45fSAndroid Build Coastguard Worker }
112*38e8c45fSAndroid Build Coastguard Worker
handleEvent(int,int events,void *)113*38e8c45fSAndroid Build Coastguard Worker int DisplayEventDispatcher::handleEvent(int, int events, void*) {
114*38e8c45fSAndroid Build Coastguard Worker if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
115*38e8c45fSAndroid Build Coastguard Worker ALOGE("Display event receiver pipe was closed or an error occurred. "
116*38e8c45fSAndroid Build Coastguard Worker "events=0x%x",
117*38e8c45fSAndroid Build Coastguard Worker events);
118*38e8c45fSAndroid Build Coastguard Worker return 0; // remove the callback
119*38e8c45fSAndroid Build Coastguard Worker }
120*38e8c45fSAndroid Build Coastguard Worker
121*38e8c45fSAndroid Build Coastguard Worker if (!(events & Looper::EVENT_INPUT)) {
122*38e8c45fSAndroid Build Coastguard Worker ALOGW("Received spurious callback for unhandled poll event. "
123*38e8c45fSAndroid Build Coastguard Worker "events=0x%x",
124*38e8c45fSAndroid Build Coastguard Worker events);
125*38e8c45fSAndroid Build Coastguard Worker return 1; // keep the callback
126*38e8c45fSAndroid Build Coastguard Worker }
127*38e8c45fSAndroid Build Coastguard Worker
128*38e8c45fSAndroid Build Coastguard Worker // Drain all pending events, keep the last vsync.
129*38e8c45fSAndroid Build Coastguard Worker nsecs_t vsyncTimestamp;
130*38e8c45fSAndroid Build Coastguard Worker PhysicalDisplayId vsyncDisplayId;
131*38e8c45fSAndroid Build Coastguard Worker uint32_t vsyncCount;
132*38e8c45fSAndroid Build Coastguard Worker VsyncEventData vsyncEventData;
133*38e8c45fSAndroid Build Coastguard Worker if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
134*38e8c45fSAndroid Build Coastguard Worker ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
135*38e8c45fSAndroid Build Coastguard Worker ", displayId=%s, count=%d, vsyncId=%" PRId64,
136*38e8c45fSAndroid Build Coastguard Worker this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
137*38e8c45fSAndroid Build Coastguard Worker vsyncEventData.preferredVsyncId());
138*38e8c45fSAndroid Build Coastguard Worker mWaitingForVsync = false;
139*38e8c45fSAndroid Build Coastguard Worker mLastVsyncCount = vsyncCount;
140*38e8c45fSAndroid Build Coastguard Worker dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
141*38e8c45fSAndroid Build Coastguard Worker }
142*38e8c45fSAndroid Build Coastguard Worker
143*38e8c45fSAndroid Build Coastguard Worker if (mWaitingForVsync) {
144*38e8c45fSAndroid Build Coastguard Worker const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
145*38e8c45fSAndroid Build Coastguard Worker const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
146*38e8c45fSAndroid Build Coastguard Worker if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
147*38e8c45fSAndroid Build Coastguard Worker ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
148*38e8c45fSAndroid Build Coastguard Worker mWaitingForVsync = false;
149*38e8c45fSAndroid Build Coastguard Worker dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
150*38e8c45fSAndroid Build Coastguard Worker ++mLastVsyncCount, vsyncEventData /* empty data */);
151*38e8c45fSAndroid Build Coastguard Worker }
152*38e8c45fSAndroid Build Coastguard Worker }
153*38e8c45fSAndroid Build Coastguard Worker
154*38e8c45fSAndroid Build Coastguard Worker return 1; // keep the callback
155*38e8c45fSAndroid Build Coastguard Worker }
156*38e8c45fSAndroid Build Coastguard Worker
processPendingEvents(nsecs_t * outTimestamp,PhysicalDisplayId * outDisplayId,uint32_t * outCount,VsyncEventData * outVsyncEventData)157*38e8c45fSAndroid Build Coastguard Worker bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
158*38e8c45fSAndroid Build Coastguard Worker PhysicalDisplayId* outDisplayId,
159*38e8c45fSAndroid Build Coastguard Worker uint32_t* outCount,
160*38e8c45fSAndroid Build Coastguard Worker VsyncEventData* outVsyncEventData) {
161*38e8c45fSAndroid Build Coastguard Worker bool gotVsync = false;
162*38e8c45fSAndroid Build Coastguard Worker DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
163*38e8c45fSAndroid Build Coastguard Worker ssize_t n;
164*38e8c45fSAndroid Build Coastguard Worker while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
165*38e8c45fSAndroid Build Coastguard Worker ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
166*38e8c45fSAndroid Build Coastguard Worker mFrameRateOverrides.reserve(n);
167*38e8c45fSAndroid Build Coastguard Worker for (ssize_t i = 0; i < n; i++) {
168*38e8c45fSAndroid Build Coastguard Worker const DisplayEventReceiver::Event& ev = buf[i];
169*38e8c45fSAndroid Build Coastguard Worker switch (ev.header.type) {
170*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
171*38e8c45fSAndroid Build Coastguard Worker // Later vsync events will just overwrite the info from earlier
172*38e8c45fSAndroid Build Coastguard Worker // ones. That's fine, we only care about the most recent.
173*38e8c45fSAndroid Build Coastguard Worker gotVsync = true;
174*38e8c45fSAndroid Build Coastguard Worker *outTimestamp = ev.header.timestamp;
175*38e8c45fSAndroid Build Coastguard Worker *outDisplayId = ev.header.displayId;
176*38e8c45fSAndroid Build Coastguard Worker *outCount = ev.vsync.count;
177*38e8c45fSAndroid Build Coastguard Worker *outVsyncEventData = ev.vsync.vsyncData;
178*38e8c45fSAndroid Build Coastguard Worker
179*38e8c45fSAndroid Build Coastguard Worker // Trace the RenderRate for this app
180*38e8c45fSAndroid Build Coastguard Worker if (ATRACE_ENABLED() && flags::trace_frame_rate_override()) {
181*38e8c45fSAndroid Build Coastguard Worker const auto frameInterval = ev.vsync.vsyncData.frameInterval;
182*38e8c45fSAndroid Build Coastguard Worker int fps = frameInterval > 0 ? 1e9f / frameInterval : 0;
183*38e8c45fSAndroid Build Coastguard Worker ATRACE_INT("RenderRate", fps);
184*38e8c45fSAndroid Build Coastguard Worker }
185*38e8c45fSAndroid Build Coastguard Worker break;
186*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
187*38e8c45fSAndroid Build Coastguard Worker if (ev.hotplug.connectionError == 0) {
188*38e8c45fSAndroid Build Coastguard Worker dispatchHotplug(ev.header.timestamp, ev.header.displayId,
189*38e8c45fSAndroid Build Coastguard Worker ev.hotplug.connected);
190*38e8c45fSAndroid Build Coastguard Worker } else {
191*38e8c45fSAndroid Build Coastguard Worker dispatchHotplugConnectionError(ev.header.timestamp,
192*38e8c45fSAndroid Build Coastguard Worker ev.hotplug.connectionError);
193*38e8c45fSAndroid Build Coastguard Worker }
194*38e8c45fSAndroid Build Coastguard Worker break;
195*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
196*38e8c45fSAndroid Build Coastguard Worker dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
197*38e8c45fSAndroid Build Coastguard Worker ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
198*38e8c45fSAndroid Build Coastguard Worker break;
199*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_NULL:
200*38e8c45fSAndroid Build Coastguard Worker dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
201*38e8c45fSAndroid Build Coastguard Worker break;
202*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
203*38e8c45fSAndroid Build Coastguard Worker mFrameRateOverrides.emplace_back(ev.frameRateOverride);
204*38e8c45fSAndroid Build Coastguard Worker break;
205*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
206*38e8c45fSAndroid Build Coastguard Worker dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
207*38e8c45fSAndroid Build Coastguard Worker std::move(mFrameRateOverrides));
208*38e8c45fSAndroid Build Coastguard Worker break;
209*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
210*38e8c45fSAndroid Build Coastguard Worker dispatchHdcpLevelsChanged(ev.header.displayId,
211*38e8c45fSAndroid Build Coastguard Worker ev.hdcpLevelsChange.connectedLevel,
212*38e8c45fSAndroid Build Coastguard Worker ev.hdcpLevelsChange.maxLevel);
213*38e8c45fSAndroid Build Coastguard Worker break;
214*38e8c45fSAndroid Build Coastguard Worker case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION:
215*38e8c45fSAndroid Build Coastguard Worker dispatchModeRejected(ev.header.displayId, ev.modeRejection.modeId);
216*38e8c45fSAndroid Build Coastguard Worker break;
217*38e8c45fSAndroid Build Coastguard Worker default:
218*38e8c45fSAndroid Build Coastguard Worker ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
219*38e8c45fSAndroid Build Coastguard Worker break;
220*38e8c45fSAndroid Build Coastguard Worker }
221*38e8c45fSAndroid Build Coastguard Worker }
222*38e8c45fSAndroid Build Coastguard Worker }
223*38e8c45fSAndroid Build Coastguard Worker if (n < 0) {
224*38e8c45fSAndroid Build Coastguard Worker ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n));
225*38e8c45fSAndroid Build Coastguard Worker }
226*38e8c45fSAndroid Build Coastguard Worker return gotVsync;
227*38e8c45fSAndroid Build Coastguard Worker }
228*38e8c45fSAndroid Build Coastguard Worker
getLatestVsyncEventData(ParcelableVsyncEventData * outVsyncEventData) const229*38e8c45fSAndroid Build Coastguard Worker status_t DisplayEventDispatcher::getLatestVsyncEventData(
230*38e8c45fSAndroid Build Coastguard Worker ParcelableVsyncEventData* outVsyncEventData) const {
231*38e8c45fSAndroid Build Coastguard Worker return mReceiver.getLatestVsyncEventData(outVsyncEventData);
232*38e8c45fSAndroid Build Coastguard Worker }
233*38e8c45fSAndroid Build Coastguard Worker
234*38e8c45fSAndroid Build Coastguard Worker } // namespace android
235