Merge "VolumeShaper: Add to native IPlayer interface"
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 46ca2c2..9e1ae94 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -95,6 +95,11 @@
std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
};
+struct CompositorTiming {
+ nsecs_t deadline{0};
+ nsecs_t interval{16666667};
+ nsecs_t presentLatency{0};
+};
// A short history of frames that are synchronized between the consumer and
// producer via deltas.
@@ -111,6 +116,8 @@
protected:
std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+
+ CompositorTiming mCompositorTiming;
};
@@ -119,6 +126,16 @@
public:
~ProducerFrameEventHistory() override;
+ // Public for testing.
+ static nsecs_t snapToNextTick(
+ nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval);
+
+ nsecs_t getNextCompositeDeadline(const nsecs_t now) const;
+ nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; }
+ nsecs_t getCompositeToPresentLatency() const {
+ return mCompositorTiming.presentLatency;
+ }
+
// virtual for testing.
virtual void updateAcquireFence(
uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
@@ -189,12 +206,15 @@
public:
~ConsumerFrameEventHistory() override;
+ void initializeCompositorTiming(const CompositorTiming& compositorTiming);
+
void addQueue(const NewFrameEventsEntry& newEntry);
void addLatch(uint64_t frameNumber, nsecs_t latchTime);
void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
void addPostComposition(uint64_t frameNumber,
const std::shared_ptr<FenceTime>& gpuCompositionDone,
- const std::shared_ptr<FenceTime>& displayPresent);
+ const std::shared_ptr<FenceTime>& displayPresent,
+ const CompositorTiming& compositorTiming);
void addRetire(uint64_t frameNumber,
const std::shared_ptr<FenceTime>& displayRetire);
void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
@@ -244,7 +264,7 @@
size_t& count);
private:
- static size_t minFlattenedSize();
+ static constexpr size_t minFlattenedSize();
size_t mIndex{0};
uint64_t mFrameNumber{0};
@@ -306,9 +326,10 @@
size_t& count);
private:
- static size_t minFlattenedSize();
+ static constexpr size_t minFlattenedSize();
std::vector<FrameEventsDelta> mDeltas;
+ CompositorTiming mCompositorTiming;
};
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index c3014b2..a3c2bfa 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -135,12 +135,18 @@
status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]);
+ status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);
+
/* Enables or disables frame timestamp tracking. It is disabled by default
* to avoid overhead during queue and dequeue for applications that don't
* need the feature. If disabled, calls to getFrameTimestamps will fail.
*/
void enableFrameTimestamps(bool enable);
+ status_t getCompositorTiming(
+ nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
+ nsecs_t* compositeToPresentLatency);
+
// See IGraphicBufferProducer::getFrameTimestamps
status_t getFrameTimestamps(uint64_t frameNumber,
nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
@@ -148,7 +154,6 @@
nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
- status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);
status_t getUniqueId(uint64_t* outId) const;
@@ -157,6 +162,7 @@
// Virtual for testing.
virtual sp<ISurfaceComposer> composerService() const;
+ virtual nsecs_t now() const;
private:
// can't be copied
@@ -204,9 +210,11 @@
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSharedBufferMode(va_list args);
int dispatchSetAutoRefresh(va_list args);
- int dispatchEnableFrameTimestamps(va_list args);
- int dispatchGetFrameTimestamps(va_list args);
int dispatchGetDisplayRefreshCycleDuration(va_list args);
+ int dispatchGetNextFrameId(va_list args);
+ int dispatchEnableFrameTimestamps(va_list args);
+ int dispatchGetCompositorTiming(va_list args);
+ int dispatchGetFrameTimestamps(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 73537bf..a6fa38a 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -235,6 +235,23 @@
ProducerFrameEventHistory::~ProducerFrameEventHistory() = default;
+nsecs_t ProducerFrameEventHistory::snapToNextTick(
+ nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval) {
+ nsecs_t tickOffset = (tickPhase - timestamp) % tickInterval;
+ // Integer modulo rounds towards 0 and not -inf before taking the remainder,
+ // so adjust the offset if it is negative.
+ if (tickOffset < 0) {
+ tickOffset += tickInterval;
+ }
+ return timestamp + tickOffset;
+}
+
+nsecs_t ProducerFrameEventHistory::getNextCompositeDeadline(
+ const nsecs_t now) const{
+ return snapToNextTick(
+ now, mCompositorTiming.deadline, mCompositorTiming.interval);
+}
+
void ProducerFrameEventHistory::updateAcquireFence(
uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
@@ -256,6 +273,8 @@
void ProducerFrameEventHistory::applyDelta(
const FrameEventHistoryDelta& delta) {
+ mCompositorTiming = delta.mCompositorTiming;
+
for (auto& d : delta.mDeltas) {
// Avoid out-of-bounds access.
if (d.mIndex >= mFrames.size()) {
@@ -346,6 +365,11 @@
ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
+void ConsumerFrameEventHistory::initializeCompositorTiming(
+ const CompositorTiming& compositorTiming) {
+ mCompositorTiming = compositorTiming;
+}
+
void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
// Overwrite all fields of the frame with default values unless set here.
FrameEvents newTimestamps;
@@ -393,7 +417,10 @@
void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber,
const std::shared_ptr<FenceTime>& gpuCompositionDone,
- const std::shared_ptr<FenceTime>& displayPresent) {
+ const std::shared_ptr<FenceTime>& displayPresent,
+ const CompositorTiming& compositorTiming) {
+ mCompositorTiming = compositorTiming;
+
FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
if (frame == nullptr) {
ALOGE_IF(mProducerWantsEvents,
@@ -450,6 +477,8 @@
void ConsumerFrameEventHistory::getAndResetDelta(
FrameEventHistoryDelta* delta) {
+ delta->mCompositorTiming = mCompositorTiming;
+
// Write these in order of frame number so that it is easy to
// add them to a FenceTimeline in the proper order producer side.
delta->mDeltas.reserve(mFramesDirty.size());
@@ -499,9 +528,8 @@
}
}
-size_t FrameEventsDelta::minFlattenedSize() {
- constexpr size_t min =
- sizeof(FrameEventsDelta::mFrameNumber) +
+constexpr size_t FrameEventsDelta::minFlattenedSize() {
+ return sizeof(FrameEventsDelta::mFrameNumber) +
sizeof(uint8_t) + // mIndex
sizeof(uint8_t) + // mAddPostCompositeCalled
sizeof(uint8_t) + // mAddRetireCalled
@@ -512,7 +540,6 @@
sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
sizeof(FrameEventsDelta::mLastRefreshStartTime) +
sizeof(FrameEventsDelta::mDequeueReadyTime);
- return min;
}
// Flattenable implementation
@@ -618,6 +645,8 @@
FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
FrameEventHistoryDelta&& src) {
+ mCompositorTiming = src.mCompositorTiming;
+
if (CC_UNLIKELY(!mDeltas.empty())) {
ALOGE("FrameEventHistoryDelta: Clobbering history.");
}
@@ -626,8 +655,9 @@
return *this;
}
-size_t FrameEventHistoryDelta::minFlattenedSize() {
- return sizeof(uint32_t);
+constexpr size_t FrameEventHistoryDelta::minFlattenedSize() {
+ return sizeof(uint32_t) + // mDeltas.size()
+ sizeof(mCompositorTiming);
}
size_t FrameEventHistoryDelta::getFlattenedSize() const {
@@ -654,6 +684,8 @@
return NO_MEMORY;
}
+ FlattenableUtils::write(buffer, size, mCompositorTiming);
+
FlattenableUtils::write(
buffer, size, static_cast<uint32_t>(mDeltas.size()));
for (auto& d : mDeltas) {
@@ -671,6 +703,8 @@
return NO_MEMORY;
}
+ FlattenableUtils::read(buffer, size, mCompositorTiming);
+
uint32_t deltaCount = 0;
FlattenableUtils::read(buffer, size, deltaCount);
if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 2fd29d5..e2f733a 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -210,6 +210,10 @@
mFlags |= SENSOR_FLAG_WAKE_UP;
}
break;
+ case SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT:
+ mStringType = SENSOR_STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT;
+ mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
+ break;
case SENSOR_TYPE_WRIST_TILT_GESTURE:
mStringType = SENSOR_STRING_TYPE_WRIST_TILT_GESTURE;
mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index 46eaf28..513b889 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -196,7 +196,8 @@
if (type == SENSOR_TYPE_PROXIMITY || type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
type == SENSOR_TYPE_TILT_DETECTOR || type == SENSOR_TYPE_WAKE_GESTURE ||
type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE ||
- type == SENSOR_TYPE_WRIST_TILT_GESTURE) {
+ type == SENSOR_TYPE_WRIST_TILT_GESTURE ||
+ type == SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT) {
wakeUpSensor = true;
}
// For now we just return the first sensor of that type we find.
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 72fa843..d285ef0 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -100,6 +100,10 @@
return ComposerService::getComposerService();
}
+nsecs_t Surface::now() const {
+ return systemTime();
+}
+
sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
return mGraphicBufferProducer;
}
@@ -142,11 +146,51 @@
outTransformMatrix);
}
+status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
+ ATRACE_CALL();
+
+ DisplayStatInfo stats;
+ status_t err = composerService()->getDisplayStats(NULL, &stats);
+
+ *outRefreshDuration = stats.vsyncPeriod;
+
+ return NO_ERROR;
+}
+
void Surface::enableFrameTimestamps(bool enable) {
Mutex::Autolock lock(mMutex);
+ // If going from disabled to enabled, get the initial values for
+ // compositor and display timing.
+ if (!mEnableFrameTimestamps && enable) {
+ FrameEventHistoryDelta delta;
+ mGraphicBufferProducer->getFrameTimestamps(&delta);
+ mFrameEventHistory->applyDelta(delta);
+ }
mEnableFrameTimestamps = enable;
}
+status_t Surface::getCompositorTiming(
+ nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
+ nsecs_t* compositeToPresentLatency) {
+ Mutex::Autolock lock(mMutex);
+ if (!mEnableFrameTimestamps) {
+ return INVALID_OPERATION;
+ }
+
+ if (compositeDeadline != nullptr) {
+ *compositeDeadline =
+ mFrameEventHistory->getNextCompositeDeadline(now());
+ }
+ if (compositeInterval != nullptr) {
+ *compositeInterval = mFrameEventHistory->getCompositeInterval();
+ }
+ if (compositeToPresentLatency != nullptr) {
+ *compositeToPresentLatency =
+ mFrameEventHistory->getCompositeToPresentLatency();
+ }
+ return NO_ERROR;
+}
+
static bool checkConsumerForUpdates(
const FrameEvents* e, const uint64_t lastFrameNumber,
const nsecs_t* outLatchTime,
@@ -260,16 +304,6 @@
return NO_ERROR;
}
-status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
- ATRACE_CALL();
-
- DisplayStatInfo stats;
- status_t err = composerService()->getDisplayStats(NULL, &stats);
-
- *outRefreshDuration = stats.vsyncPeriod;
-
- return NO_ERROR;
-}
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
Surface* c = getSelf(window);
@@ -831,15 +865,21 @@
case NATIVE_WINDOW_SET_AUTO_REFRESH:
res = dispatchSetAutoRefresh(args);
break;
+ case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
+ res = dispatchGetDisplayRefreshCycleDuration(args);
+ break;
+ case NATIVE_WINDOW_GET_NEXT_FRAME_ID:
+ res = dispatchGetNextFrameId(args);
+ break;
case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS:
res = dispatchEnableFrameTimestamps(args);
break;
+ case NATIVE_WINDOW_GET_COMPOSITOR_TIMING:
+ res = dispatchGetCompositorTiming(args);
+ break;
case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
res = dispatchGetFrameTimestamps(args);
break;
- case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
- res = dispatchGetDisplayRefreshCycleDuration(args);
- break;
default:
res = NAME_NOT_FOUND;
break;
@@ -960,14 +1000,33 @@
return setAutoRefresh(autoRefresh);
}
+int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
+ nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
+ return getDisplayRefreshCycleDuration(outRefreshDuration);
+}
+
+int Surface::dispatchGetNextFrameId(va_list args) {
+ uint64_t* nextFrameId = va_arg(args, uint64_t*);
+ *nextFrameId = getNextFrameNumber();
+ return NO_ERROR;
+}
+
int Surface::dispatchEnableFrameTimestamps(va_list args) {
bool enable = va_arg(args, int);
enableFrameTimestamps(enable);
return NO_ERROR;
}
+int Surface::dispatchGetCompositorTiming(va_list args) {
+ nsecs_t* compositeDeadline = va_arg(args, int64_t*);
+ nsecs_t* compositeInterval = va_arg(args, int64_t*);
+ nsecs_t* compositeToPresentLatency = va_arg(args, int64_t*);
+ return getCompositorTiming(compositeDeadline, compositeInterval,
+ compositeToPresentLatency);
+}
+
int Surface::dispatchGetFrameTimestamps(va_list args) {
- uint32_t framesAgo = va_arg(args, uint32_t);
+ uint64_t frameId = va_arg(args, uint64_t);
nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*);
nsecs_t* outAcquireTime = va_arg(args, int64_t*);
nsecs_t* outLatchTime = va_arg(args, int64_t*);
@@ -978,18 +1037,13 @@
nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
nsecs_t* outReleaseTime = va_arg(args, int64_t*);
- return getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
+ return getFrameTimestamps(frameId,
outRequestedPresentTime, outAcquireTime, outLatchTime,
outFirstRefreshStartTime, outLastRefreshStartTime,
outGlCompositionDoneTime, outDisplayPresentTime,
outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
}
-int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
- nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
- return getDisplayRefreshCycleDuration(outRefreshDuration);
-}
-
int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 412c0f6..5298027 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -479,8 +479,17 @@
return mFakeSurfaceComposer;
}
+ nsecs_t now() const override {
+ return mNow;
+ }
+
+ void setNow(nsecs_t now) {
+ mNow = now;
+ }
+
public:
sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+ nsecs_t mNow = 0;
// mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
// but this raw pointer gives access to test functionality.
@@ -500,10 +509,12 @@
struct RefreshEvents {
RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart)
- : mFenceMap(fenceMap),
- kStartTime(refreshStart + 1),
- kGpuCompositionDoneTime(refreshStart + 2),
- kPresentTime(refreshStart + 3) {}
+ : mFenceMap(fenceMap),
+ kCompositorTiming(
+ {refreshStart, refreshStart + 1, refreshStart + 2 }),
+ kStartTime(refreshStart + 3),
+ kGpuCompositionDoneTime(refreshStart + 4),
+ kPresentTime(refreshStart + 5) {}
void signalPostCompositeFences() {
mFenceMap.signalAllForTest(
@@ -516,6 +527,8 @@
FenceAndFenceTime mGpuCompositionDone { mFenceMap };
FenceAndFenceTime mPresent { mFenceMap };
+ const CompositorTiming kCompositorTiming;
+
const nsecs_t kStartTime;
const nsecs_t kGpuCompositionDoneTime;
const nsecs_t kPresentTime;
@@ -592,14 +605,20 @@
native_window_set_buffer_count(mWindow.get(), 4);
}
+ void disableFrameTimestamps() {
+ mFakeConsumer->mGetFrameTimestampsEnabled = false;
+ native_window_enable_frame_timestamps(mWindow.get(), 0);
+ mFrameTimestampsEnabled = false;
+ }
+
void enableFrameTimestamps() {
mFakeConsumer->mGetFrameTimestampsEnabled = true;
native_window_enable_frame_timestamps(mWindow.get(), 1);
mFrameTimestampsEnabled = true;
}
- int getAllFrameTimestamps(uint32_t framesAgo) {
- return native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ int getAllFrameTimestamps(uint64_t frameId) {
+ return native_window_get_frame_timestamps(mWindow.get(), frameId,
&outRequestedPresentTime, &outAcquireTime, &outLatchTime,
&outFirstRefreshStartTime, &outLastRefreshStartTime,
&outGpuCompositionDoneTime, &outDisplayPresentTime,
@@ -619,6 +638,13 @@
outReleaseTime = -1;
}
+ uint64_t getNextFrameId() {
+ uint64_t frameId = -1;
+ int status = native_window_get_next_frame_id(mWindow.get(), &frameId);
+ EXPECT_EQ(status, NO_ERROR);
+ return frameId;
+ }
+
void dequeueAndQueue(uint64_t frameIndex) {
int fence = -1;
ANativeWindowBuffer* buffer = nullptr;
@@ -674,7 +700,8 @@
oldFrame->mRefreshes[2].mGpuCompositionDone.mFenceTime :
FenceTime::NO_FENCE;
mCfeh->addPostComposition(nOldFrame, gpuDoneFenceTime,
- oldFrame->mRefreshes[2].mPresent.mFenceTime);
+ oldFrame->mRefreshes[2].mPresent.mFenceTime,
+ oldFrame->mRefreshes[2].kCompositorTiming);
}
// Latch the new frame.
@@ -691,7 +718,8 @@
std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
}
mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
- newFrame->mRefreshes[0].mPresent.mFenceTime);
+ newFrame->mRefreshes[0].mPresent.mFenceTime,
+ newFrame->mRefreshes[0].kCompositorTiming);
// Retire the previous buffer just after compositing the new buffer.
if (oldFrame != nullptr) {
@@ -703,7 +731,8 @@
newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
FenceTime::NO_FENCE;
mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
- newFrame->mRefreshes[1].mPresent.mFenceTime);
+ newFrame->mRefreshes[1].mPresent.mFenceTime,
+ newFrame->mRefreshes[1].kCompositorTiming);
}
void QueryPresentRetireSupported(
@@ -733,7 +762,8 @@
int64_t outDequeueReadyTime = -1;
int64_t outReleaseTime = -1;
- FrameEvents mFrames[2] { { mFenceMap, 1000 }, { mFenceMap, 2000 } };
+ FrameEvents mFrames[3] {
+ { mFenceMap, 1000 }, { mFenceMap, 2000 }, { mFenceMap, 3000 } };
};
@@ -748,6 +778,8 @@
EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+ const uint64_t fId = getNextFrameId();
+
// Verify the producer doesn't get frame timestamps piggybacked on dequeue.
ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
@@ -761,27 +793,58 @@
EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
// Verify attempts to get frame timestamps fail.
- const uint32_t framesAgo = 0;
- int result = getAllFrameTimestamps(framesAgo);
+ int result = getAllFrameTimestamps(fId);
EXPECT_EQ(INVALID_OPERATION, result);
EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+ // Verify compositor timing query fails.
+ nsecs_t compositeDeadline = 0;
+ nsecs_t compositeInterval = 0;
+ nsecs_t compositeToPresentLatency = 0;
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(INVALID_OPERATION, result);
}
// This test verifies that the frame timestamps are retrieved if explicitly
// enabled via native_window_enable_frame_timestamps.
TEST_F(GetFrameTimestampsTest, EnabledSimple) {
+ CompositorTiming initialCompositorTiming {
+ 1000000000, // 1s deadline
+ 16666667, // 16ms interval
+ 50000000, // 50ms present latency
+ };
+ mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
enableFrameTimestamps();
+ // Verify the compositor timing query gets the initial compositor values
+ // after timststamps are enabled; even before the first frame is queued
+ // or dequeued.
+ nsecs_t compositeDeadline = 0;
+ nsecs_t compositeInterval = 0;
+ nsecs_t compositeToPresentLatency = 0;
+ mSurface->setNow(initialCompositorTiming.deadline - 1);
+ int result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+ EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+ EXPECT_EQ(initialCompositorTiming.presentLatency,
+ compositeToPresentLatency);
+
int fence;
ANativeWindowBuffer* buffer;
EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
- EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
+
+ const uint64_t fId1 = getNextFrameId();
// Verify getFrameTimestamps is piggybacked on dequeue.
ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
- EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
NewFrameEventsEntry f1;
f1.frameNumber = 1;
@@ -798,14 +861,13 @@
ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
EXPECT_EQ(1u, mFakeConsumer->mLastAddedFrameNumber);
- EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
// Verify queries for timestamps that the producer doesn't know about
// triggers a call to see if the consumer has any new timestamps.
- const uint32_t framesAgo = 0;
- int result = getAllFrameTimestamps(framesAgo);
+ result = getAllFrameTimestamps(fId1);
EXPECT_EQ(NO_ERROR, result);
- EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
}
void GetFrameTimestampsTest::QueryPresentRetireSupported(
@@ -833,16 +895,245 @@
QueryPresentRetireSupported(false, true);
}
-// This test verifies that:
-// 1) The timestamps recorded in the consumer's FrameTimestampsHistory are
-// properly retrieved by the producer for the correct frames.
-// 2) When framesAgo is 0, it is querying for the most recently queued frame.
+TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
+ nsecs_t phase = 4000;
+ nsecs_t interval = 1000;
+
+ // Timestamp in previous interval.
+ nsecs_t timestamp = 3500;
+ EXPECT_EQ(4000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+
+ // Timestamp in next interval.
+ timestamp = 4500;
+ EXPECT_EQ(5000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+
+ // Timestamp multiple intervals before.
+ timestamp = 2500;
+ EXPECT_EQ(3000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+
+ // Timestamp multiple intervals after.
+ timestamp = 6500;
+ EXPECT_EQ(7000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+
+ // Timestamp on previous interval.
+ timestamp = 3000;
+ EXPECT_EQ(3000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+
+ // Timestamp on next interval.
+ timestamp = 5000;
+ EXPECT_EQ(5000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+
+ // Timestamp equal to phase.
+ timestamp = 4000;
+ EXPECT_EQ(4000, ProducerFrameEventHistory::snapToNextTick(
+ timestamp, phase, interval));
+}
+
+// int(big_timestamp / interval) < 0, which can cause a crash or invalid result
+// if the number of intervals elapsed is internally stored in an int.
+TEST_F(GetFrameTimestampsTest, SnapToNextTickOverflow) {
+ nsecs_t phase = 0;
+ nsecs_t interval = 4000;
+ nsecs_t big_timestamp = 8635916564000;
+ int32_t intervals = big_timestamp / interval;
+
+ EXPECT_LT(intervals, 0);
+ EXPECT_EQ(8635916564000, ProducerFrameEventHistory::snapToNextTick(
+ big_timestamp, phase, interval));
+ EXPECT_EQ(8635916564000, ProducerFrameEventHistory::snapToNextTick(
+ big_timestamp, big_timestamp, interval));
+}
+
+// This verifies the compositor timing is updated by refresh events
+// and piggy backed on a queue, dequeue, and enabling of timestamps..
+TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) {
+ CompositorTiming initialCompositorTiming {
+ 1000000000, // 1s deadline
+ 16666667, // 16ms interval
+ 50000000, // 50ms present latency
+ };
+ mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+ enableFrameTimestamps();
+
+ // We get the initial values before any frames are submitted.
+ nsecs_t compositeDeadline = 0;
+ nsecs_t compositeInterval = 0;
+ nsecs_t compositeToPresentLatency = 0;
+ mSurface->setNow(initialCompositorTiming.deadline - 1);
+ int result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+ EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+ EXPECT_EQ(initialCompositorTiming.presentLatency,
+ compositeToPresentLatency);
+
+ const uint64_t fId1 = getNextFrameId();
+ dequeueAndQueue(0);
+ addFrameEvents(true, NO_FRAME_INDEX, 0);
+
+ // Still get the initial values because the frame events for frame 0
+ // didn't get a chance to piggyback on a queue or dequeue yet.
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+ EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+ EXPECT_EQ(initialCompositorTiming.presentLatency,
+ compositeToPresentLatency);
+
+ const uint64_t fId2 = getNextFrameId();
+ dequeueAndQueue(1);
+ addFrameEvents(true, 0, 1);
+
+ // Now expect the composite values associated with frame 1.
+ mSurface->setNow(mFrames[0].mRefreshes[1].kCompositorTiming.deadline);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.deadline,
+ compositeDeadline);
+ EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.interval,
+ compositeInterval);
+ EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.presentLatency,
+ compositeToPresentLatency);
+
+ dequeueAndQueue(2);
+ addFrameEvents(true, 1, 2);
+
+ // Now expect the composite values associated with frame 2.
+ mSurface->setNow(mFrames[1].mRefreshes[1].kCompositorTiming.deadline);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.deadline,
+ compositeDeadline);
+ EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.interval,
+ compositeInterval);
+ EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.presentLatency,
+ compositeToPresentLatency);
+
+ // Re-enabling frame timestamps should get the latest values.
+ disableFrameTimestamps();
+ enableFrameTimestamps();
+
+ // Now expect the composite values associated with frame 3.
+ mSurface->setNow(mFrames[2].mRefreshes[1].kCompositorTiming.deadline);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.deadline,
+ compositeDeadline);
+ EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.interval,
+ compositeInterval);
+ EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.presentLatency,
+ compositeToPresentLatency);
+}
+
+// This verifies the compositor deadline properly snaps to the the next
+// deadline based on the current time.
+TEST_F(GetFrameTimestampsTest, CompositorTimingDeadlineSnaps) {
+ CompositorTiming initialCompositorTiming {
+ 1000000000, // 1s deadline
+ 16666667, // 16ms interval
+ 50000000, // 50ms present latency
+ };
+ mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+ enableFrameTimestamps();
+
+ nsecs_t compositeDeadline = 0;
+ nsecs_t compositeInterval = 0;
+ nsecs_t compositeToPresentLatency = 0;
+
+ // A "now" just before the deadline snaps to the deadline.
+ mSurface->setNow(initialCompositorTiming.deadline - 1);
+ int result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+ nsecs_t expectedDeadline = initialCompositorTiming.deadline;
+ EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+ const uint64_t fId1 = getNextFrameId();
+ dequeueAndQueue(0);
+ addFrameEvents(true, NO_FRAME_INDEX, 0);
+
+ // A "now" just after the deadline snaps properly.
+ mSurface->setNow(initialCompositorTiming.deadline + 1);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ expectedDeadline =
+ initialCompositorTiming.deadline +initialCompositorTiming.interval;
+ EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+ const uint64_t fId2 = getNextFrameId();
+ dequeueAndQueue(1);
+ addFrameEvents(true, 0, 1);
+
+ // A "now" just after the next interval snaps properly.
+ mSurface->setNow(
+ mFrames[0].mRefreshes[1].kCompositorTiming.deadline +
+ mFrames[0].mRefreshes[1].kCompositorTiming.interval + 1);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ expectedDeadline =
+ mFrames[0].mRefreshes[1].kCompositorTiming.deadline +
+ mFrames[0].mRefreshes[1].kCompositorTiming.interval * 2;
+ EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+ dequeueAndQueue(2);
+ addFrameEvents(true, 1, 2);
+
+ // A "now" over 1 interval before the deadline snaps properly.
+ mSurface->setNow(
+ mFrames[1].mRefreshes[1].kCompositorTiming.deadline -
+ mFrames[1].mRefreshes[1].kCompositorTiming.interval - 1);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ expectedDeadline =
+ mFrames[1].mRefreshes[1].kCompositorTiming.deadline -
+ mFrames[1].mRefreshes[1].kCompositorTiming.interval;
+ EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+ // Re-enabling frame timestamps should get the latest values.
+ disableFrameTimestamps();
+ enableFrameTimestamps();
+
+ // A "now" over 2 intervals before the deadline snaps properly.
+ mSurface->setNow(
+ mFrames[2].mRefreshes[1].kCompositorTiming.deadline -
+ mFrames[2].mRefreshes[1].kCompositorTiming.interval * 2 - 1);
+ result = native_window_get_compositor_timing(mWindow.get(),
+ &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+ EXPECT_EQ(NO_ERROR, result);
+ expectedDeadline =
+ mFrames[2].mRefreshes[1].kCompositorTiming.deadline -
+ mFrames[2].mRefreshes[1].kCompositorTiming.interval * 2;
+ EXPECT_EQ(expectedDeadline, compositeDeadline);
+}
+
+// This verifies the timestamps recorded in the consumer's
+// FrameTimestampsHistory are properly retrieved by the producer for the
+// correct frames.
TEST_F(GetFrameTimestampsTest, TimestampsAssociatedWithCorrectFrame) {
enableFrameTimestamps();
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
mFrames[0].signalQueueFences();
+ const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
mFrames[1].signalQueueFences();
@@ -853,9 +1144,8 @@
mFrames[1].signalRefreshFences();
// Verify timestamps are correct for frame 1.
- uint32_t framesAgo = 1;
resetTimestamps();
- int result = getAllFrameTimestamps(framesAgo);
+ int result = getAllFrameTimestamps(fId1);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
@@ -870,9 +1160,8 @@
EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
// Verify timestamps are correct for frame 2.
- framesAgo = 0;
resetTimestamps();
- result = getAllFrameTimestamps(framesAgo);
+ result = getAllFrameTimestamps(fId2);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
@@ -893,9 +1182,8 @@
enableFrameTimestamps();
mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
- const uint32_t framesAgo = 0;
-
// Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
// Verify queue-related timestamps for f1 are available immediately in the
@@ -903,7 +1191,7 @@
// acquire fence.
resetTimestamps();
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
&outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
@@ -915,7 +1203,7 @@
mFrames[0].signalQueueFences();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ result = native_window_get_frame_timestamps(mWindow.get(), fId1,
&outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
@@ -924,6 +1212,7 @@
EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
// Dequeue and queue frame 2.
+ const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
// Verify queue-related timestamps for f2 are available immediately in the
@@ -931,7 +1220,7 @@
// acquire fence.
resetTimestamps();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ result = native_window_get_frame_timestamps(mWindow.get(), fId2,
&outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
@@ -943,7 +1232,7 @@
mFrames[1].signalQueueFences();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ result = native_window_get_frame_timestamps(mWindow.get(), fId2,
&outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
@@ -961,6 +1250,7 @@
mFrames[0].signalQueueFences();
// Dequeue and queue frame 2.
+ const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
mFrames[1].signalQueueFences();
@@ -971,9 +1261,8 @@
mFrames[1].signalRefreshFences();
// Verify a request for no timestamps doesn't result in a sync call.
- const uint32_t framesAgo = 0;
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ int result = native_window_get_frame_timestamps(mWindow.get(), fId2,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr);
EXPECT_EQ(NO_ERROR, result);
@@ -987,6 +1276,7 @@
mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
// Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
mFrames[0].signalQueueFences();
@@ -1001,10 +1291,9 @@
// fence has been signaled.
// Note: A sync call is necessary here since the events triggered by
// addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
- uint32_t framesAgo = 1;
resetTimestamps();
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- int result = getAllFrameTimestamps(framesAgo);
+ int result = getAllFrameTimestamps(fId1);
EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1021,10 +1310,9 @@
// Verify available timestamps are correct for frame 1 again, before any
// fence has been signaled.
// This time a sync call should not be necessary.
- framesAgo = 1;
resetTimestamps();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = getAllFrameTimestamps(framesAgo);
+ result = getAllFrameTimestamps(fId1);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1043,10 +1331,9 @@
mFrames[0].signalReleaseFences();
// Verify all timestamps are available without a sync call.
- framesAgo = 1;
resetTimestamps();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = getAllFrameTimestamps(framesAgo);
+ result = getAllFrameTimestamps(fId1);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1069,9 +1356,8 @@
enableFrameTimestamps();
mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
- const uint32_t framesAgo = 1;
-
// Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
mFrames[0].signalQueueFences();
@@ -1088,7 +1374,7 @@
// addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
resetTimestamps();
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- int result = getAllFrameTimestamps(framesAgo);
+ int result = getAllFrameTimestamps(fId1);
EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1110,7 +1396,7 @@
// sync call.
resetTimestamps();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = getAllFrameTimestamps(framesAgo);
+ result = getAllFrameTimestamps(fId1);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1132,10 +1418,12 @@
mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
// Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
mFrames[0].signalQueueFences();
// Dequeue and queue frame 2.
+ const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
mFrames[1].signalQueueFences();
@@ -1146,10 +1434,9 @@
// fence has been signaled.
// Note: A sync call is necessary here since the events triggered by
// addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
- uint32_t framesAgo = 1;
resetTimestamps();
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- int result = getAllFrameTimestamps(framesAgo);
+ int result = getAllFrameTimestamps(fId1);
EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1167,15 +1454,14 @@
mFrames[0].signalReleaseFences();
mFrames[1].signalRefreshFences();
- // Verify querying for all timestmaps of f2 does not do a sync call.
- // Even though the lastRefresh, retire, dequeueReady, and release times aren't
+ // Verify querying for all timestmaps of f2 does not do a sync call. Even
+ // though the lastRefresh, retire, dequeueReady, and release times aren't
// available, a sync call should not occur because it's not possible for f2
// to encounter the final value for those events until another frame is
// queued.
- framesAgo = 0;
resetTimestamps();
oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- result = getAllFrameTimestamps(framesAgo);
+ result = getAllFrameTimestamps(fId2);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -1200,14 +1486,14 @@
displayPresentSupported, displayRetireSupported);
// Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
// Verify a query for the Present and Retire times do not trigger
// a sync call if they are not supported.
- const uint32_t framesAgo = 0;
resetTimestamps();
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
- int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
displayPresentSupported ? nullptr : &outDisplayPresentTime,
displayRetireSupported ? nullptr : &outDisplayRetireTime,
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 027c18d..6572cab 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -632,22 +632,31 @@
#ifndef EGL_ANDROID_get_frame_timestamps
#define EGL_ANDROID_get_frame_timestamps 1
#define EGL_TIMESTAMPS_ANDROID 0x314D
-#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
-#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
-#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
-#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
-#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
-#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
-#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
-#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
-#define EGL_READS_DONE_TIME_ANDROID 0x3157
+#define EGL_COMPOSITE_DEADLINE_ANDROID 0x314E
+#define EGL_COMPOSITE_INTERVAL_ANDROID 0x314F
+#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150
+#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151
+#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
+#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3156
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
+#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
+#define EGL_READS_DONE_TIME_ANDROID 0x315A
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name);
+EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
#else
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
#endif
#endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 2782ed7..ab3ac3a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -216,10 +216,16 @@
(__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
// EGL_ANDROID_get_frame_timestamps
+ { "eglGetNextFrameIdANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID },
+ { "eglGetCompositorTimingANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID },
+ { "eglGetCompositorTimingSupportedANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID },
{ "eglGetFrameTimestampsANDROID",
(__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
- { "eglQueryTimestampSupportedANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglQueryTimestampSupportedANDROID },
+ { "eglGetFrameTimestampSupportedANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID },
};
/*
@@ -2048,8 +2054,133 @@
return EGL_FALSE;
}
+EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR *frameId) {
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (!s->win.get()) {
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ uint64_t nextFrameId = 0;
+ status_t ret = native_window_get_next_frame_id(s->win.get(), &nextFrameId);
+
+ if (ret != NO_ERROR) {
+ // This should not happen. Return an error that is not in the spec
+ // so it's obvious something is very wrong.
+ ALOGE("eglGetNextFrameId: Unexpected error.");
+ return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+
+ *frameId = nextFrameId;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (!s->win.get()) {
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ nsecs_t* compositeDeadline = nullptr;
+ nsecs_t* compositeInterval = nullptr;
+ nsecs_t* compositeToPresentLatency = nullptr;
+
+ for (int i = 0; i < numTimestamps; i++) {
+ switch (names[i]) {
+ case EGL_COMPOSITE_DEADLINE_ANDROID:
+ compositeDeadline = &values[i];
+ break;
+ case EGL_COMPOSITE_INTERVAL_ANDROID:
+ compositeInterval = &values[i];
+ break;
+ case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+ compositeToPresentLatency = &values[i];
+ break;
+ default:
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+ }
+
+ status_t ret = native_window_get_compositor_timing(s->win.get(),
+ compositeDeadline, compositeInterval, compositeToPresentLatency);
+
+ switch (ret) {
+ case NO_ERROR:
+ return EGL_TRUE;
+ case INVALID_OPERATION:
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ default:
+ // This should not happen. Return an error that is not in the spec
+ // so it's obvious something is very wrong.
+ ALOGE("eglGetCompositorTiming: Unexpected error.");
+ return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+}
+
+EGLBoolean eglGetCompositorTimingSupportedANDROID(
+ EGLDisplay dpy, EGLSurface surface, EGLint name)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ ANativeWindow* window = s->win.get();
+ if (!window) {
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ switch (name) {
+#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
+ case EGL_COMPOSITE_DEADLINE_ANDROID:
+ case EGL_COMPOSITE_INTERVAL_ANDROID:
+ case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+ return EGL_TRUE;
+#endif
+ default:
+ return EGL_FALSE;
+ }
+}
+
EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
- EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
+ EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps,
EGLnsecsANDROID *values)
{
clearError();
@@ -2118,7 +2249,7 @@
}
}
- status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo,
+ status_t ret = native_window_get_frame_timestamps(s->win.get(), frameId,
requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
lastRefreshStartTime, GLCompositionDoneTime, displayPresentTime,
displayRetireTime, dequeueReadyTime, releaseTime);
@@ -2135,12 +2266,13 @@
default:
// This should not happen. Return an error that is not in the spec
// so it's obvious something is very wrong.
+ ALOGE("eglGetFrameTimestamps: Unexpected error.");
return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
}
}
-EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface,
- EGLint timestamp)
+EGLBoolean eglGetFrameTimestampSupportedANDROID(
+ EGLDisplay dpy, EGLSurface surface, EGLint timestamp)
{
clearError();
@@ -2163,6 +2295,9 @@
switch (timestamp) {
#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
+ case EGL_COMPOSITE_DEADLINE_ANDROID:
+ case EGL_COMPOSITE_INTERVAL_ANDROID:
+ case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
case EGL_REQUESTED_PRESENT_TIME_ANDROID:
case EGL_RENDERING_COMPLETE_TIME_ANDROID:
case EGL_COMPOSITION_LATCH_TIME_ANDROID:
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index 7aa0d30..f946418 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -57,26 +57,36 @@
New Procedures and Functions
- EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
- EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
- EGLnsecsANDROID *values);
+ EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR *frameId);
- EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
- surface, EGLint timestamp);
+ EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy,
+ EGLSurface surface, EGLint numTimestamps,
+ const EGLint *names, EGLnsecsANDROID *values);
+
+ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR frameId, EGLint numTimestamps,
+ const EGLint *timestamps, EGLnsecsANDROID *values);
+
+ EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy,
+ EGLSurface surface, EGLint timestamp);
New Tokens
EGL_TIMESTAMPS_ANDROID 0x314D
- EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
- EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
- EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
- EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
- EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
- EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
- EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
- EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
- EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
- EGL_READS_DONE_TIME_ANDROID 0x3157
+ EGL_COMPOSITE_DEADLINE_ANDROID 0x314E
+ EGL_COMPOSITE_INTERVAL_ANDROID 0x314F
+ EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150
+ EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151
+ EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152
+ EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
+ EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
+ EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
+ EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3156
+ EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
+ EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
+ EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
+ EGL_READS_DONE_TIME_ANDROID 0x315A
Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
"Surface Attributes", page 43:
@@ -95,23 +105,54 @@
The function
- EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface
- surface, EGLint framesAgo, EGLint numTimestamps,
+ EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR *frameId);
+
+ Returns an identifier for the next frame to be swapped. The identifier can
+ be used to correlate a particular eglSwapBuffers with its timestamps in
+ eglGetFrameTimestampsANDROID. If any error is generated, the function will
+ return EGL_FALSE.
+
+ The function
+
+ EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy,
+ EGLSurface surface, EGLint numTimestamps,
+ const EGLint *names, EGLnsecsANDROID *values);
+
+ allows querying anticipated timestamps and durations related to the
+ composition and display of a window surface. The values are not associated
+ with a particular frame and can be retrieved before the first swap.
+
+ The eglGetCompositorTimingANDROID function takes an array of names to
+ query and returns their values in the corresponding indices of the values
+ array. The possible names that can be queried are:
+ - EGL_COMPOSITE_DEADLINE_ANDROID - The timestamp of the next time the
+ compositor will begin composition. This is effectively the deadline
+ for when the compositor must receive a newly queued frame.
+ - EGL_COMPOSITE_INTERVAL_ANDROID - The time delta between subsequent
+ composition events.
+ - EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID - The time delta between
+ the start of composition and the expected present time of that
+ composition. This can be used to estimate the latency of the
+ actual present time.
+
+ The function
+
+ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy,
+ EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps,
const EGLint *timestamps, EGLnsecsANDROID *values);
- allows querying various timestamps related to the composition and display of
- a window surface.
+ allows querying various timestamps related to the composition and display
+ of specific frames of a window surface.
- The framesAgo parameter indicates how many frames before the last queued
- frame to query. So a value of zero would indicate that the query is for the
- last queued frame. Note that the implementation maintains a limited history
- of timestamp data. If a query is made for a frame whose timestamp history
- no longer exists then EGL_BAD_ACCESS is generated. If timestamp collection
- has not been enabled for the surface then EGL_BAD_SURFACE is generated.
- Timestamps for events that will not occur or have not yet occurred will be
- zero. Timestamp queries that are not supported will generate an
- EGL_BAD_PARAMETER error. If any error is generated the function will return
- EGL_FALSE.
+ The frameId indicates which frame to query. The implementation maintains a
+ limited history of timestamp data. If a query is made for a frame whose
+ timestamp history no longer exists then EGL_BAD_ACCESS is generated. If
+ timestamp collection has not been enabled for the surface then
+ EGL_BAD_SURFACE is generated. Timestamps for events that will not occur or
+ have not yet occurred will be zero. Timestamp queries that are not
+ supported will generate an EGL_BAD_PARAMETER error. If any error is
+ generated the function will return EGL_FALSE.
The eglGetFrameTimestampsANDROID function takes an array of timestamps to
query and returns timestamps in the corresponding indices of the values
@@ -151,12 +192,19 @@
purpose of display/composition were completed for this frame.
Not all implementations may support all of the above timestamp queries. The
- function
+ functions
- EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
- surface, EGLint timestamp);
+ EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy,
+ EGLSurface surface, EGLint name);
- allows querying which timestamps are supported on the implementation."
+ and
+
+ EGLBoolean eglGetFrameTimestampsSupportedANDROID(EGLDisplay dpy,
+ EGLSurface surface, EGLint timestamp);
+
+ allows querying which values are supported by the implementations of
+ eglGetCompositoTimingANDROID and eglGetFrameTimestampsSupportedANDROID
+ respectively."
Issues
@@ -175,3 +223,9 @@
- Add EGL_COMPOSITION_LATCH_TIME_ANDROID,
EGL_LAST_COMPOSITION_START_TIME_ANDROID, and
EGL_DEQUEUE_READY_TIME_ANDROID.
+
+#4 (Brian Anderson, January 10, 2017)
+ - Use an absolute frameId rather than a relative framesAgo.
+
+#5 (Brian Anderson, January 13, 2017)
+ - Add eglGetCompositorTimingANDROID.
diff --git a/opengl/specs/README b/opengl/specs/README
index 8a3a7aa..0c49023 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -1,5 +1,5 @@
This directory contains OpenGL ES and EGL extension specifications that have
-been or are being defined for Android.
+been or are being defined for Android.
The table below tracks usage of EGL enumerant values that have been reserved
for use by Android extensions.
@@ -20,14 +20,17 @@
0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
0x314D EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x314E EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x314F EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3150 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3151 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3152 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3153 EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3154 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3155 EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3156 EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3157 EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3158 - 0x315F (unused)
+0x314E EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x314F EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3150 EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3151 EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3152 EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3153 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3154 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3155 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3156 EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3157 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3158 EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3159 EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x315A EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x315B - 0x315F (unused)
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index c41630a..d61f26f 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -10,6 +10,7 @@
OrientationSensor.cpp \
RecentEventLogger.cpp \
RotationVectorSensor.cpp \
+ SensorDevice.cpp \
SensorDirectConnection.cpp \
SensorEventConnection.cpp \
SensorFusion.cpp \
@@ -25,13 +26,6 @@
LOCAL_CFLAGS += -fvisibility=hidden
-ifeq ($(ENABLE_TREBLE), true)
-LOCAL_SRC_FILES += SensorDeviceTreble.cpp
-LOCAL_CFLAGS += -DENABLE_TREBLE=1
-else
-LOCAL_SRC_FILES += SensorDevice.cpp
-endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
@@ -42,10 +36,6 @@
libui \
libgui \
libcrypto \
-
-ifeq ($(ENABLE_TREBLE), true)
-
-LOCAL_SHARED_LIBRARIES += \
libbase \
libhidlbase \
libhidltransport \
@@ -55,8 +45,6 @@
LOCAL_STATIC_LIBRARIES := \
android.hardware.sensors@1.0-convert
-endif # ENABLE_TREBLE
-
LOCAL_MODULE:= libsensorservice
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index de0321d..3edd50b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -14,138 +14,167 @@
* limitations under the License.
*/
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
-#include "SensorDevice.h"
-#include "SensorService.h"
-
-
-#include <binder/BinderService.h>
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-#include <cutils/ashmem.h>
-#include <hardware/sensors.h>
+#include <android-base/logging.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/Singleton.h>
-#include <inttypes.h>
-#include <math.h>
-#include <sys/mman.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sstream>
-#include <unistd.h>
+#include "SensorDevice.h"
+#include "SensorService.h"
+
+#include <sensors/convert.h>
+
+using android::hardware::hidl_vec;
+
+using namespace android::hardware::sensors::V1_0;
+using namespace android::hardware::sensors::V1_0::implementation;
namespace android {
// ---------------------------------------------------------------------------
ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
-SensorDevice::SensorDevice()
- : mSensorDevice(0),
- mSensorModule(0) {
- status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
- (hw_module_t const**)&mSensorModule);
-
- ALOGE_IF(err, "couldn't load %s module (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
-
- if (mSensorModule) {
- err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
-
- ALOGE_IF(err, "couldn't open device for module %s (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
-
- if (mSensorDevice) {
-
- sensor_t const* list;
- ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
-
- if (mSensorDevice->common.version < SENSORS_DEVICE_API_VERSION_1_3) {
- ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3, ignoring sensors reported by this device");
- count = 0;
- }
-
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i<size_t(count) ; i++) {
- mActivationCount.add(list[i].handle, model);
- mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- list[i].handle, 0);
- }
- }
+static status_t StatusFromResult(Result result) {
+ switch (result) {
+ case Result::OK:
+ return OK;
+ case Result::BAD_VALUE:
+ return BAD_VALUE;
+ case Result::PERMISSION_DENIED:
+ return PERMISSION_DENIED;
+ case Result::INVALID_OPERATION:
+ return INVALID_OPERATION;
+ case Result::NO_MEMORY:
+ return NO_MEMORY;
}
}
+SensorDevice::SensorDevice() {
+ mSensors = ISensors::getService();
+
+ if (mSensors == NULL) {
+ return;
+ }
+
+ mSensors->getSensorsList(
+ [&](const auto &list) {
+ const size_t count = list.size();
+
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i=0 ; i < count; i++) {
+ sensor_t sensor;
+ convertToSensor(list[i], &sensor);
+ mSensorList.push_back(sensor);
+
+ mActivationCount.add(list[i].sensorHandle, model);
+
+ mSensors->activate(list[i].sensorHandle, 0 /* enabled */);
+ }
+ });
+
+ mIsDirectReportSupported =
+ (mSensors->unregisterDirectChannel(-1) != Result::INVALID_OPERATION);
+}
+
void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
if (connected) {
Info model;
mActivationCount.add(handle, model);
- mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), handle, 0);
+ mSensors->activate(handle, 0 /* enabled */);
} else {
mActivationCount.removeItem(handle);
}
}
std::string SensorDevice::dump() const {
- if (!mSensorModule) return "HAL not initialized\n";
+ if (mSensors == NULL) return "HAL not initialized\n";
String8 result;
- sensor_t const* list;
- int count = mSensorModule->get_sensors_list(mSensorModule, &list);
+ mSensors->getSensorsList([&](const auto &list) {
+ const size_t count = list.size();
- result.appendFormat("HAL: %s (%s), version %#010x\n",
- mSensorModule->common.name,
- mSensorModule->common.author,
- getHalDeviceVersion());
- result.appendFormat("Total %d h/w sensors, %zu running:\n", count, mActivationCount.size());
+ result.appendFormat(
+ "Total %zu h/w sensors, %zu running:\n",
+ count,
+ mActivationCount.size());
- Mutex::Autolock _l(mLock);
- for (int i = 0 ; i < count ; i++) {
- const Info& info = mActivationCount.valueFor(list[i].handle);
- if (info.batchParams.isEmpty()) continue;
- result.appendFormat("0x%08x) active-count = %zu; ", list[i].handle,
- info.batchParams.size());
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0 ; i < count ; i++) {
+ const Info& info = mActivationCount.valueFor(
+ list[i].sensorHandle);
- result.append("sampling_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- const BatchParams& params = info.batchParams.valueAt(j);
- result.appendFormat("%.1f%s", params.batchDelay / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f);
+ if (info.batchParams.isEmpty()) continue;
+ result.appendFormat(
+ "0x%08x) active-count = %zu; ",
+ list[i].sensorHandle,
+ info.batchParams.size());
- result.append("batching_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
- result.appendFormat("%.1f%s", params.batchTimeout / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
- }
+ result.append("sampling_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& params = info.batchParams.valueAt(j);
+ result.appendFormat(
+ "%.1f%s",
+ params.batchDelay / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+ result.appendFormat(
+ "}, selected = %.1f ms; ",
+ info.bestBatchParams.batchDelay / 1e6f);
+
+ result.append("batching_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ BatchParams params = info.batchParams.valueAt(j);
+
+ result.appendFormat(
+ "%.1f%s",
+ params.batchTimeout / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+
+ result.appendFormat(
+ "}, selected = %.1f ms\n",
+ info.bestBatchParams.batchTimeout / 1e6f);
+ }
+ });
+
return result.string();
}
ssize_t SensorDevice::getSensorList(sensor_t const** list) {
- if (!mSensorModule) return NO_INIT;
- ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list);
- return count;
+ *list = &mSensorList[0];
+
+ return mSensorList.size();
}
status_t SensorDevice::initCheck() const {
- return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT;
+ return mSensors != NULL ? NO_ERROR : NO_INIT;
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (!mSensorDevice) return NO_INIT;
- ssize_t c;
- do {
- c = mSensorDevice->poll(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
- buffer, count);
- } while (c == -EINTR);
- return c;
+ if (mSensors == NULL) return NO_INIT;
+
+ ssize_t err;
+
+ mSensors->poll(
+ count,
+ [&](auto result,
+ const auto &events,
+ const auto &dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEvents(events, dynamicSensorsAdded, buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = StatusFromResult(result);
+ }
+ });
+
+ return err;
}
void SensorDevice::autoDisable(void *ident, int handle) {
@@ -155,7 +184,8 @@
}
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (!mSensorDevice) return NO_INIT;
+ if (mSensors == NULL) return NO_INIT;
+
status_t err(NO_ERROR);
bool actuateHardware = false;
@@ -187,24 +217,30 @@
} else {
ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
+ // If a connected dynamic sensor is deactivated, remove it from the
+ // dictionary.
+ auto it = mConnectedDynamicSensors.find(handle);
+ if (it != mConnectedDynamicSensors.end()) {
+ delete it->second;
+ mConnectedDynamicSensors.erase(it);
+ }
+
if (info.removeBatchParamsForIdent(ident) >= 0) {
if (info.numActiveClients() == 0) {
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else {
- const int halVersion = getHalDeviceVersion();
- if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
- // Call batch for this sensor with the previously calculated best effort
- // batch_rate and timeout. One of the apps has unregistered for sensor
- // events, and the best effort batch parameters might have changed.
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- mSensorDevice->batch(mSensorDevice, handle,info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- }
+ // Call batch for this sensor with the previously calculated best effort
+ // batch_rate and timeout. One of the apps has unregistered for sensor
+ // events, and the best effort batch parameters might have changed.
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
}
} else {
// sensor wasn't enabled for this ident
@@ -218,8 +254,7 @@
if (actuateHardware) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
enabled);
- err = mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
+ err = StatusFromResult(mSensors->activate(handle, enabled));
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
strerror(-err));
@@ -229,31 +264,21 @@
}
}
- // On older devices which do not support batch, call setDelay().
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
- info.bestBatchParams.batchDelay);
- mSensorDevice->setDelay(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- handle, info.bestBatchParams.batchDelay);
- }
return err;
}
-status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
- if (!mSensorDevice) return NO_INIT;
+status_t SensorDevice::batch(
+ void* ident,
+ int handle,
+ int flags,
+ int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) {
+ if (mSensors == NULL) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
- const int halVersion = getHalDeviceVersion();
- if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 && maxBatchReportLatencyNs != 0) {
- // Batch is not supported on older devices return invalid operation.
- return INVALID_OPERATION;
- }
-
ALOGD_IF(DEBUG_CONNECTIONS,
"SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
@@ -282,21 +307,17 @@
status_t err(NO_ERROR);
// If the min period or min timeout has changed since the last batch call, call batch.
if (prevBestBatchParams != info.bestBatchParams) {
- if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- err = mSensorDevice->batch(mSensorDevice, handle, info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- } else {
- // For older devices which do not support batch, call setDelay() after activate() is
- // called. Some older devices may not support calling setDelay before activate(), so
- // call setDelay in SensorDevice::activate() method.
- }
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ err = StatusFromResult(
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
if (err != NO_ERROR) {
ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
- mSensorDevice, handle,
+ mSensors.get(), handle,
info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
info.bestBatchParams.batchTimeout, strerror(-err));
info.removeBatchParamsForIdent(ident);
@@ -306,7 +327,7 @@
}
status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
- if (!mSensorDevice) return NO_INIT;
+ if (mSensors == NULL) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
@@ -325,22 +346,20 @@
BatchParams& params = info.batchParams.editValueAt(index);
params.batchDelay = samplingPeriodNs;
info.selectBatchParams();
- return mSensorDevice->setDelay(reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- handle, info.bestBatchParams.batchDelay);
+
+ return StatusFromResult(
+ mSensors->batch(handle, info.bestBatchParams.batchDelay, 0));
}
int SensorDevice::getHalDeviceVersion() const {
- if (!mSensorDevice) return -1;
- return mSensorDevice->common.version;
+ if (mSensors == NULL) return -1;
+ return SENSORS_DEVICE_API_VERSION_1_4;
}
status_t SensorDevice::flush(void* ident, int handle) {
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
- return INVALID_OPERATION;
- }
if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
- return mSensorDevice->flush(mSensorDevice, handle);
+ return StatusFromResult(mSensors->flush(handle));
}
bool SensorDevice::isClientDisabled(void* ident) {
@@ -356,7 +375,6 @@
Mutex::Autolock _l(mLock);
mDisabledClients.clear();
ALOGI("cleared mDisabledClients");
- const int halVersion = getHalDeviceVersion();
for (size_t i = 0; i< mActivationCount.size(); ++i) {
Info& info = mActivationCount.editValueAt(i);
if (info.batchParams.isEmpty()) continue;
@@ -364,42 +382,32 @@
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
sensor_handle);
- status_t err(NO_ERROR);
- if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
- err = mSensorDevice->batch(mSensorDevice, sensor_handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
- }
+ status_t err = StatusFromResult(
+ mSensors->batch(
+ sensor_handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
if (err == NO_ERROR) {
- err = mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- sensor_handle, 1);
+ err = StatusFromResult(
+ mSensors->activate(sensor_handle, 1 /* enabled */));
ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
}
-
- if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
- err = mSensorDevice->setDelay(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- sensor_handle, info.bestBatchParams.batchDelay);
- ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
- }
}
}
void SensorDevice::disableAllSensors() {
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
const Info& info = mActivationCount.valueAt(i);
// Check if this sensor has been activated previously and disable it.
if (info.batchParams.size() > 0) {
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
sensor_handle);
- mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
- sensor_handle, 0);
+ mSensors->activate(sensor_handle, 0 /* enabled */);
+
// Add all the connections that were registered for this sensor to the disabled
// clients list.
for (size_t j = 0; j < info.batchParams.size(); ++j) {
@@ -410,25 +418,27 @@
}
}
-status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) {
- ALOGD_IF(DEBUG_CONNECTIONS,
- "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
- injected_sensor_event->sensor,
- injected_sensor_event->timestamp, injected_sensor_event->data[0],
- injected_sensor_event->data[1], injected_sensor_event->data[2],
- injected_sensor_event->data[3], injected_sensor_event->data[4],
- injected_sensor_event->data[5]);
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
- return INVALID_OPERATION;
- }
- return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event);
+status_t SensorDevice::injectSensorData(
+ const sensors_event_t *injected_sensor_event) {
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor,
+ injected_sensor_event->timestamp, injected_sensor_event->data[0],
+ injected_sensor_event->data[1], injected_sensor_event->data[2],
+ injected_sensor_event->data[3], injected_sensor_event->data[4],
+ injected_sensor_event->data[5]);
+
+ Event ev;
+ convertFromSensorEvent(*injected_sensor_event, &ev);
+
+ return StatusFromResult(mSensors->injectSensorData(ev));
}
status_t SensorDevice::setMode(uint32_t mode) {
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
- return INVALID_OPERATION;
- }
- return mSensorModule->set_operation_mode(mode);
+
+ return StatusFromResult(
+ mSensors->setOperationMode(
+ static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
}
// ---------------------------------------------------------------------------
@@ -491,44 +501,139 @@
}
int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
-
- if (!isDirectReportSupported()) {
- return INVALID_OPERATION;
- }
-
Mutex::Autolock _l(mLock);
- int32_t channelHandle = mSensorDevice->register_direct_channel(
- mSensorDevice, memory, -1 /*channel_handle*/);
- return channelHandle;
+ SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ SharedMemFormat format;
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ format = SharedMemFormat::SENSORS_EVENT;
+
+ SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<uint32_t>(memory->size),
+ .memoryHandle = memory->handle,
+ };
+
+ int32_t ret;
+ mSensors->registerDirectChannel(mem,
+ [&ret](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ ret = channelHandle;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ });
+ return ret;
}
void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
Mutex::Autolock _l(mLock);
-
- mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
+ mSensors->unregisterDirectChannel(channelHandle);
}
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
- const struct sensors_direct_cfg_t *config) {
-
- if (!isDirectReportSupported()) {
- return INVALID_OPERATION;
- }
-
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
+ int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
Mutex::Autolock _l(mLock);
- int32_t ret = mSensorDevice->config_direct_report(
- mSensorDevice, sensorHandle, channelHandle, config);
- ALOGE_IF(ret < 0, "SensorDevice::configureDirectChannel ret %d", ret);
+ RateLevel rate;
+ switch(config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ int32_t ret;
+ mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+ [&ret, rate] (auto result, auto token) {
+ if (rate == RateLevel::STOP) {
+ ret = StatusFromResult(result);
+ } else {
+ if (result == Result::OK) {
+ ret = token;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }
+ });
+
return ret;
}
bool SensorDevice::isDirectReportSupported() const {
- bool ret = mSensorDevice->register_direct_channel != nullptr
- && mSensorDevice->config_direct_report != nullptr;
- return ret;
+ return mIsDirectReportSupported;
}
+
+void SensorDevice::convertToSensorEvent(
+ const Event &src, sensors_event_t *dst) {
+ ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
+ src, dst);
+
+ if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) {
+ const DynamicSensorInfo &dyn = src.u.dynamic;
+
+ dst->dynamic_sensor_meta.connected = dyn.connected;
+ dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
+ if (dyn.connected) {
+ auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+ CHECK(it != mConnectedDynamicSensors.end());
+
+ dst->dynamic_sensor_meta.sensor = it->second;
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ dyn.uuid.data(),
+ sizeof(dst->dynamic_sensor_meta.uuid));
+ }
+ }
+}
+
+void SensorDevice::convertToSensorEvents(
+ const hidl_vec<Event> &src,
+ const hidl_vec<SensorInfo> &dynamicSensorsAdded,
+ sensors_event_t *dst) {
+ // Allocate a sensor_t structure for each dynamic sensor added and insert
+ // it into the dictionary of connected dynamic sensors keyed by handle.
+ for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
+ const SensorInfo &info = dynamicSensorsAdded[i];
+
+ auto it = mConnectedDynamicSensors.find(info.sensorHandle);
+ CHECK(it == mConnectedDynamicSensors.end());
+
+ sensor_t *sensor = new sensor_t;
+ convertToSensor(info, sensor);
+
+ mConnectedDynamicSensors.insert(
+ std::make_pair(sensor->handle, sensor));
+ }
+
+ for (size_t i = 0; i < src.size(); ++i) {
+ convertToSensorEvent(src[i], &dst[i]);
+ }
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
-
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 7dd256a..7f95429 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -20,19 +20,16 @@
#include "SensorServiceUtils.h"
#include <gui/Sensor.h>
+#include <stdint.h>
+#include <sys/types.h>
#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
#include <utils/String8.h>
-#include <stdint.h>
-#include <sys/types.h>
#include <string>
-
-#ifdef ENABLE_TREBLE
#include <map>
#include "android/hardware/sensors/1.0/ISensors.h"
-#endif
// ---------------------------------------------------------------------------
@@ -76,14 +73,10 @@
virtual std::string dump() const;
private:
friend class Singleton<SensorDevice>;
-#ifdef ENABLE_TREBLE
+
sp<android::hardware::sensors::V1_0::ISensors> mSensors;
Vector<sensor_t> mSensorList;
std::map<int32_t, sensor_t*> mConnectedDynamicSensors;
-#else
- sensors_poll_device_1_t* mSensorDevice;
- struct sensors_module_t* mSensorModule;
-#endif
static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
mutable Mutex mLock; // protect mActivationCount[].batchParams
@@ -138,7 +131,6 @@
bool isClientDisabled(void* ident);
bool isClientDisabledLocked(void* ident);
-#ifdef ENABLE_TREBLE
using Event = hardware::sensors::V1_0::Event;
using SensorInfo = hardware::sensors::V1_0::SensorInfo;
@@ -150,7 +142,6 @@
sensors_event_t *dst);
bool mIsDirectReportSupported;
-#endif // ENABLE_TREBLE
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDeviceTreble.cpp b/services/sensorservice/SensorDeviceTreble.cpp
deleted file mode 100644
index 3edd50b..0000000
--- a/services/sensorservice/SensorDeviceTreble.cpp
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * Copyright (C) 2010 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 <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android-base/logging.h>
-#include <utils/Atomic.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-
-#include "SensorDevice.h"
-#include "SensorService.h"
-
-#include <sensors/convert.h>
-
-using android::hardware::hidl_vec;
-
-using namespace android::hardware::sensors::V1_0;
-using namespace android::hardware::sensors::V1_0::implementation;
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
-
-static status_t StatusFromResult(Result result) {
- switch (result) {
- case Result::OK:
- return OK;
- case Result::BAD_VALUE:
- return BAD_VALUE;
- case Result::PERMISSION_DENIED:
- return PERMISSION_DENIED;
- case Result::INVALID_OPERATION:
- return INVALID_OPERATION;
- case Result::NO_MEMORY:
- return NO_MEMORY;
- }
-}
-
-SensorDevice::SensorDevice() {
- mSensors = ISensors::getService();
-
- if (mSensors == NULL) {
- return;
- }
-
- mSensors->getSensorsList(
- [&](const auto &list) {
- const size_t count = list.size();
-
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i < count; i++) {
- sensor_t sensor;
- convertToSensor(list[i], &sensor);
- mSensorList.push_back(sensor);
-
- mActivationCount.add(list[i].sensorHandle, model);
-
- mSensors->activate(list[i].sensorHandle, 0 /* enabled */);
- }
- });
-
- mIsDirectReportSupported =
- (mSensors->unregisterDirectChannel(-1) != Result::INVALID_OPERATION);
-}
-
-void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
- if (connected) {
- Info model;
- mActivationCount.add(handle, model);
- mSensors->activate(handle, 0 /* enabled */);
- } else {
- mActivationCount.removeItem(handle);
- }
-}
-
-std::string SensorDevice::dump() const {
- if (mSensors == NULL) return "HAL not initialized\n";
-
- String8 result;
- mSensors->getSensorsList([&](const auto &list) {
- const size_t count = list.size();
-
- result.appendFormat(
- "Total %zu h/w sensors, %zu running:\n",
- count,
- mActivationCount.size());
-
- Mutex::Autolock _l(mLock);
- for (size_t i = 0 ; i < count ; i++) {
- const Info& info = mActivationCount.valueFor(
- list[i].sensorHandle);
-
- if (info.batchParams.isEmpty()) continue;
- result.appendFormat(
- "0x%08x) active-count = %zu; ",
- list[i].sensorHandle,
- info.batchParams.size());
-
- result.append("sampling_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- const BatchParams& params = info.batchParams.valueAt(j);
- result.appendFormat(
- "%.1f%s",
- params.batchDelay / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat(
- "}, selected = %.1f ms; ",
- info.bestBatchParams.batchDelay / 1e6f);
-
- result.append("batching_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
-
- result.appendFormat(
- "%.1f%s",
- params.batchTimeout / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
-
- result.appendFormat(
- "}, selected = %.1f ms\n",
- info.bestBatchParams.batchTimeout / 1e6f);
- }
- });
-
- return result.string();
-}
-
-ssize_t SensorDevice::getSensorList(sensor_t const** list) {
- *list = &mSensorList[0];
-
- return mSensorList.size();
-}
-
-status_t SensorDevice::initCheck() const {
- return mSensors != NULL ? NO_ERROR : NO_INIT;
-}
-
-ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (mSensors == NULL) return NO_INIT;
-
- ssize_t err;
-
- mSensors->poll(
- count,
- [&](auto result,
- const auto &events,
- const auto &dynamicSensorsAdded) {
- if (result == Result::OK) {
- convertToSensorEvents(events, dynamicSensorsAdded, buffer);
- err = (ssize_t)events.size();
- } else {
- err = StatusFromResult(result);
- }
- });
-
- return err;
-}
-
-void SensorDevice::autoDisable(void *ident, int handle) {
- Info& info( mActivationCount.editValueFor(handle) );
- Mutex::Autolock _l(mLock);
- info.removeBatchParamsForIdent(ident);
-}
-
-status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (mSensors == NULL) return NO_INIT;
-
- status_t err(NO_ERROR);
- bool actuateHardware = false;
-
- Mutex::Autolock _l(mLock);
- Info& info( mActivationCount.editValueFor(handle) );
-
- ALOGD_IF(DEBUG_CONNECTIONS,
- "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
- ident, handle, enabled, info.batchParams.size());
-
- if (enabled) {
- ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
-
- if (isClientDisabledLocked(ident)) {
- ALOGE("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d",
- ident, handle);
- return INVALID_OPERATION;
- }
-
- if (info.batchParams.indexOfKey(ident) >= 0) {
- if (info.numActiveClients() == 1) {
- // This is the first connection, we need to activate the underlying h/w sensor.
- actuateHardware = true;
- }
- } else {
- // Log error. Every activate call should be preceded by a batch() call.
- ALOGE("\t >>>ERROR: activate called without batch");
- }
- } else {
- ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
-
- // If a connected dynamic sensor is deactivated, remove it from the
- // dictionary.
- auto it = mConnectedDynamicSensors.find(handle);
- if (it != mConnectedDynamicSensors.end()) {
- delete it->second;
- mConnectedDynamicSensors.erase(it);
- }
-
- if (info.removeBatchParamsForIdent(ident) >= 0) {
- if (info.numActiveClients() == 0) {
- // This is the last connection, we need to de-activate the underlying h/w sensor.
- actuateHardware = true;
- } else {
- // Call batch for this sensor with the previously calculated best effort
- // batch_rate and timeout. One of the apps has unregistered for sensor
- // events, and the best effort batch parameters might have changed.
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- mSensors->batch(
- handle,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- }
- } else {
- // sensor wasn't enabled for this ident
- }
-
- if (isClientDisabledLocked(ident)) {
- return NO_ERROR;
- }
- }
-
- if (actuateHardware) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
- enabled);
- err = StatusFromResult(mSensors->activate(handle, enabled));
- ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
- strerror(-err));
-
- if (err != NO_ERROR && enabled) {
- // Failure when enabling the sensor. Clean up on failure.
- info.removeBatchParamsForIdent(ident);
- }
- }
-
- return err;
-}
-
-status_t SensorDevice::batch(
- void* ident,
- int handle,
- int flags,
- int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
- if (mSensors == NULL) return NO_INIT;
-
- if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
- samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
- }
-
- ALOGD_IF(DEBUG_CONNECTIONS,
- "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
- ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
-
- Mutex::Autolock _l(mLock);
- Info& info(mActivationCount.editValueFor(handle));
-
- if (info.batchParams.indexOfKey(ident) < 0) {
- BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs);
- info.batchParams.add(ident, params);
- } else {
- // A batch has already been called with this ident. Update the batch parameters.
- info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
- }
-
- BatchParams prevBestBatchParams = info.bestBatchParams;
- // Find the minimum of all timeouts and batch_rates for this sensor.
- info.selectBatchParams();
-
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> curr_period=%" PRId64 " min_period=%" PRId64
- " curr_timeout=%" PRId64 " min_timeout=%" PRId64,
- prevBestBatchParams.batchDelay, info.bestBatchParams.batchDelay,
- prevBestBatchParams.batchTimeout, info.bestBatchParams.batchTimeout);
-
- status_t err(NO_ERROR);
- // If the min period or min timeout has changed since the last batch call, call batch.
- if (prevBestBatchParams != info.bestBatchParams) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- err = StatusFromResult(
- mSensors->batch(
- handle,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout));
- if (err != NO_ERROR) {
- ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
- mSensors.get(), handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout, strerror(-err));
- info.removeBatchParamsForIdent(ident);
- }
- }
- return err;
-}
-
-status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
- if (mSensors == NULL) return NO_INIT;
- if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
- samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
- }
- Mutex::Autolock _l(mLock);
- if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
- Info& info( mActivationCount.editValueFor(handle) );
- // If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
- // Calling setDelay() in batch mode is an invalid operation.
- if (info.bestBatchParams.batchTimeout != 0) {
- return INVALID_OPERATION;
- }
- ssize_t index = info.batchParams.indexOfKey(ident);
- if (index < 0) {
- return BAD_INDEX;
- }
- BatchParams& params = info.batchParams.editValueAt(index);
- params.batchDelay = samplingPeriodNs;
- info.selectBatchParams();
-
- return StatusFromResult(
- mSensors->batch(handle, info.bestBatchParams.batchDelay, 0));
-}
-
-int SensorDevice::getHalDeviceVersion() const {
- if (mSensors == NULL) return -1;
- return SENSORS_DEVICE_API_VERSION_1_4;
-}
-
-status_t SensorDevice::flush(void* ident, int handle) {
- if (isClientDisabled(ident)) return INVALID_OPERATION;
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
- return StatusFromResult(mSensors->flush(handle));
-}
-
-bool SensorDevice::isClientDisabled(void* ident) {
- Mutex::Autolock _l(mLock);
- return isClientDisabledLocked(ident);
-}
-
-bool SensorDevice::isClientDisabledLocked(void* ident) {
- return mDisabledClients.indexOf(ident) >= 0;
-}
-
-void SensorDevice::enableAllSensors() {
- Mutex::Autolock _l(mLock);
- mDisabledClients.clear();
- ALOGI("cleared mDisabledClients");
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
- Info& info = mActivationCount.editValueAt(i);
- if (info.batchParams.isEmpty()) continue;
- info.selectBatchParams();
- const int sensor_handle = mActivationCount.keyAt(i);
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
- sensor_handle);
- status_t err = StatusFromResult(
- mSensors->batch(
- sensor_handle,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout));
- ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
-
- if (err == NO_ERROR) {
- err = StatusFromResult(
- mSensors->activate(sensor_handle, 1 /* enabled */));
- ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
- }
- }
-}
-
-void SensorDevice::disableAllSensors() {
- Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
- const Info& info = mActivationCount.valueAt(i);
- // Check if this sensor has been activated previously and disable it.
- if (info.batchParams.size() > 0) {
- const int sensor_handle = mActivationCount.keyAt(i);
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
- sensor_handle);
- mSensors->activate(sensor_handle, 0 /* enabled */);
-
- // Add all the connections that were registered for this sensor to the disabled
- // clients list.
- for (size_t j = 0; j < info.batchParams.size(); ++j) {
- mDisabledClients.add(info.batchParams.keyAt(j));
- ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
- }
- }
- }
-}
-
-status_t SensorDevice::injectSensorData(
- const sensors_event_t *injected_sensor_event) {
- ALOGD_IF(DEBUG_CONNECTIONS,
- "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
- injected_sensor_event->sensor,
- injected_sensor_event->timestamp, injected_sensor_event->data[0],
- injected_sensor_event->data[1], injected_sensor_event->data[2],
- injected_sensor_event->data[3], injected_sensor_event->data[4],
- injected_sensor_event->data[5]);
-
- Event ev;
- convertFromSensorEvent(*injected_sensor_event, &ev);
-
- return StatusFromResult(mSensors->injectSensorData(ev));
-}
-
-status_t SensorDevice::setMode(uint32_t mode) {
-
- return StatusFromResult(
- mSensors->setOperationMode(
- static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
-}
-
-// ---------------------------------------------------------------------------
-
-int SensorDevice::Info::numActiveClients() {
- SensorDevice& device(SensorDevice::getInstance());
- int num = 0;
- for (size_t i = 0; i < batchParams.size(); ++i) {
- if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
- ++num;
- }
- }
- return num;
-}
-
-status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
- int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
- ssize_t index = batchParams.indexOfKey(ident);
- if (index < 0) {
- ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)",
- ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index));
- return BAD_INDEX;
- }
- BatchParams& params = batchParams.editValueAt(index);
- params.flags = flags;
- params.batchDelay = samplingPeriodNs;
- params.batchTimeout = maxBatchReportLatencyNs;
- return NO_ERROR;
-}
-
-void SensorDevice::Info::selectBatchParams() {
- BatchParams bestParams(0, -1, -1);
- SensorDevice& device(SensorDevice::getInstance());
-
- for (size_t i = 0; i < batchParams.size(); ++i) {
- if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
- BatchParams params = batchParams.valueAt(i);
- if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
- bestParams.batchDelay = params.batchDelay;
- }
- if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
- bestParams.batchTimeout = params.batchTimeout;
- }
- }
- bestBatchParams = bestParams;
-}
-
-ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) {
- ssize_t idx = batchParams.removeItem(ident);
- if (idx >= 0) {
- selectBatchParams();
- }
- return idx;
-}
-
-void SensorDevice::notifyConnectionDestroyed(void* ident) {
- Mutex::Autolock _l(mLock);
- mDisabledClients.remove(ident);
-}
-
-int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
- Mutex::Autolock _l(mLock);
-
- SharedMemType type;
- switch (memory->type) {
- case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
- type = SharedMemType::ASHMEM;
- break;
- case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- type = SharedMemType::GRALLOC;
- break;
- default:
- return BAD_VALUE;
- }
-
- SharedMemFormat format;
- if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
- return BAD_VALUE;
- }
- format = SharedMemFormat::SENSORS_EVENT;
-
- SharedMemInfo mem = {
- .type = type,
- .format = format,
- .size = static_cast<uint32_t>(memory->size),
- .memoryHandle = memory->handle,
- };
-
- int32_t ret;
- mSensors->registerDirectChannel(mem,
- [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = StatusFromResult(result);
- }
- });
- return ret;
-}
-
-void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
- Mutex::Autolock _l(mLock);
- mSensors->unregisterDirectChannel(channelHandle);
-}
-
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
- int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
- Mutex::Autolock _l(mLock);
-
- RateLevel rate;
- switch(config->rate_level) {
- case SENSOR_DIRECT_RATE_STOP:
- rate = RateLevel::STOP;
- break;
- case SENSOR_DIRECT_RATE_NORMAL:
- rate = RateLevel::NORMAL;
- break;
- case SENSOR_DIRECT_RATE_FAST:
- rate = RateLevel::FAST;
- break;
- case SENSOR_DIRECT_RATE_VERY_FAST:
- rate = RateLevel::VERY_FAST;
- break;
- default:
- return BAD_VALUE;
- }
-
- int32_t ret;
- mSensors->configDirectReport(sensorHandle, channelHandle, rate,
- [&ret, rate] (auto result, auto token) {
- if (rate == RateLevel::STOP) {
- ret = StatusFromResult(result);
- } else {
- if (result == Result::OK) {
- ret = token;
- } else {
- ret = StatusFromResult(result);
- }
- }
- });
-
- return ret;
-}
-
-bool SensorDevice::isDirectReportSupported() const {
- return mIsDirectReportSupported;
-}
-
-void SensorDevice::convertToSensorEvent(
- const Event &src, sensors_event_t *dst) {
- ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
- src, dst);
-
- if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) {
- const DynamicSensorInfo &dyn = src.u.dynamic;
-
- dst->dynamic_sensor_meta.connected = dyn.connected;
- dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
- if (dyn.connected) {
- auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- CHECK(it != mConnectedDynamicSensors.end());
-
- dst->dynamic_sensor_meta.sensor = it->second;
-
- memcpy(dst->dynamic_sensor_meta.uuid,
- dyn.uuid.data(),
- sizeof(dst->dynamic_sensor_meta.uuid));
- }
- }
-}
-
-void SensorDevice::convertToSensorEvents(
- const hidl_vec<Event> &src,
- const hidl_vec<SensorInfo> &dynamicSensorsAdded,
- sensors_event_t *dst) {
- // Allocate a sensor_t structure for each dynamic sensor added and insert
- // it into the dictionary of connected dynamic sensors keyed by handle.
- for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
- const SensorInfo &info = dynamicSensorsAdded[i];
-
- auto it = mConnectedDynamicSensors.find(info.sensorHandle);
- CHECK(it == mConnectedDynamicSensors.end());
-
- sensor_t *sensor = new sensor_t;
- convertToSensor(info, sensor);
-
- mConnectedDynamicSensors.insert(
- std::make_pair(sensor->handle, sensor));
- }
-
- for (size_t i = 0; i < src.size(); ++i) {
- convertToSensorEvent(src[i], &dst[i]);
- }
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index 1996a00..34cd8dd 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -54,6 +54,7 @@
case SENSOR_TYPE_STATIONARY_DETECT:
case SENSOR_TYPE_MOTION_DETECT:
case SENSOR_TYPE_HEART_BEAT:
+ case SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT:
return 1;
default:
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index 2b603cc..a6171f5 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -2010,7 +2010,8 @@
mZ(0),
mReleaseFence(),
mHwc1Id(0),
- mHasUnsupportedPlaneAlpha(false) {}
+ mHasUnsupportedPlaneAlpha(false),
+ mHasUnsupportedBackgroundColor(false) {}
bool HWC2On1Adapter::SortLayersByZ::operator()(
const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs)
@@ -2466,7 +2467,7 @@
}
}
- if (mHwc1DisplayMap.count(0) == 0) {
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
return false;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d2b26c2..4a281d4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -914,6 +914,10 @@
const sp<GraphicBuffer>& buffer,
uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
{
+#ifdef BYPASS_IHWC
+ *outSlot = slot;
+ *outBuffer = buffer;
+#else
if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
// default to slot 0
slot = 0;
@@ -934,6 +938,7 @@
// update cache
mBuffers[slot] = buffer;
}
+#endif
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6e0a489..a854aec 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -155,6 +155,10 @@
flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
#endif
mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
+
+ CompositorTiming compositorTiming;
+ flinger->getCompositorTiming(&compositorTiming);
+ mFrameEventHistory.initializeCompositorTiming(compositorTiming);
}
void Layer::onFirstRef() {
@@ -1882,10 +1886,10 @@
return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
}
-bool Layer::onPostComposition(
- const std::shared_ptr<FenceTime>& glDoneFence,
+bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
- const std::shared_ptr<FenceTime>& retireFence) {
+ const std::shared_ptr<FenceTime>& retireFence,
+ const CompositorTiming& compositorTiming) {
mAcquireTimeline.updateSignalTimes();
mReleaseTimeline.updateSignalTimes();
@@ -1898,7 +1902,7 @@
{
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
- glDoneFence, presentFence);
+ glDoneFence, presentFence, compositorTiming);
mFrameEventHistory.addRetire(mPreviousFrameNumber,
retireFence);
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 12166a8..8227dae 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -296,10 +296,10 @@
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- bool onPostComposition(
- const std::shared_ptr<FenceTime>& glDoneFence,
+ bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
- const std::shared_ptr<FenceTime>& retireFence);
+ const std::shared_ptr<FenceTime>& retireFence,
+ const CompositorTiming& compositorTiming);
#ifdef USE_HWC2
// If a buffer was replaced this frame, release the former buffer
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cbc209d..d2dddba 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -139,7 +139,7 @@
static int64_t vsyncPhaseOffsetNs = getVsyncEventPhaseOffsetNs();
// This is the phase offset at which SurfaceFlinger's composition runs.
-static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
+static constexpr int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
// ---------------------------------------------------------------------------
@@ -1126,6 +1126,11 @@
}
}
+void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
+ std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+ *compositorTiming = mCompositorTiming;
+}
+
void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) {
ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
if (disp == DisplayDevice::DISPLAY_PRIMARY) {
@@ -1265,7 +1270,8 @@
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
- mPreviousPresentFence->getSignalTime() == INT64_MAX;
+ (mPreviousPresentFence->getSignalTime() ==
+ Fence::SIGNAL_TIME_PENDING);
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (mPropagateBackpressure && frameMissed) {
signalLayerUpdate();
@@ -1314,7 +1320,7 @@
setUpHWComposer();
doDebugFlashRegions();
doComposition();
- postComposition();
+ postComposition(refreshStartTime);
mPreviousPresentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
@@ -1389,7 +1395,61 @@
}
}
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::updateCompositorTiming(
+ nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime) {
+ // Update queue of past composite+present times and determine the
+ // most recently known composite to present latency.
+ mCompositePresentTimes.push({compositeTime, presentFenceTime});
+ nsecs_t compositeToPresentLatency = -1;
+ while (!mCompositePresentTimes.empty()) {
+ CompositePresentTime& cpt = mCompositePresentTimes.front();
+ // Cached values should have been updated before calling this method,
+ // which helps avoid duplicate syscalls.
+ nsecs_t displayTime = cpt.display->getCachedSignalTime();
+ if (displayTime == Fence::SIGNAL_TIME_PENDING) {
+ break;
+ }
+ compositeToPresentLatency = displayTime - cpt.composite;
+ mCompositePresentTimes.pop();
+ }
+
+ // Don't let mCompositePresentTimes grow unbounded, just in case.
+ while (mCompositePresentTimes.size() > 16) {
+ mCompositePresentTimes.pop();
+ }
+
+ // Integer division and modulo round toward 0 not -inf, so we need to
+ // treat negative and positive offsets differently.
+ nsecs_t idealLatency = (sfVsyncPhaseOffsetNs >= 0) ?
+ (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
+ ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+
+ // Snap the latency to a value that removes scheduling jitter from the
+ // composition and present times, which often have >1ms of jitter.
+ // Reducing jitter is important if an app attempts to extrapolate
+ // something (such as user input) to an accurate diasplay time.
+ // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+ // with (presentLatency % interval).
+ nsecs_t snappedCompositeToPresentLatency = -1;
+ if (compositeToPresentLatency >= 0) {
+ nsecs_t bias = vsyncInterval / 2;
+ int64_t extraVsyncs =
+ (compositeToPresentLatency - idealLatency + bias) /
+ vsyncInterval;
+ nsecs_t extraLatency = extraVsyncs * vsyncInterval;
+ snappedCompositeToPresentLatency = idealLatency + extraLatency;
+ }
+
+ std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+ mCompositorTiming.deadline = vsyncPhase - idealLatency;
+ mCompositorTiming.interval = vsyncInterval;
+ if (snappedCompositeToPresentLatency >= 0) {
+ mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+ }
+}
+
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
{
ATRACE_CALL();
ALOGV("postComposition");
@@ -1424,9 +1484,19 @@
} else {
retireFenceTime = &displayFenceTime;
}
+
+ nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
+ nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+
+ // We use the refreshStartTime which might be sampled a little later than
+ // when we started doing work for this frame, but that should be okay
+ // since updateCompositorTiming has snapping logic.
+ updateCompositorTiming(
+ vsyncPhase, vsyncInterval, refreshStartTime, displayFenceTime);
+
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
- *presentFenceTime, *retireFenceTime);
+ *presentFenceTime, *retireFenceTime, mCompositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
@@ -1471,9 +1541,8 @@
if (mHasPoweredOff) {
mHasPoweredOff = false;
} else {
- nsecs_t period = mPrimaryDispSync.getPeriod();
nsecs_t elapsedTime = currentTime - mLastSwapTime;
- size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+ size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
if (numPeriods < NUM_BUCKETS - 1) {
mFrameBuckets[numPeriods] += elapsedTime;
} else {
@@ -2876,6 +2945,11 @@
const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+ {
+ std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+ mCompositorTiming.interval = period;
+ }
}
void SurfaceFlinger::initializeDisplays() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 02e4a0c..f52bd2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -42,6 +42,7 @@
#include <ui/PixelFormat.h>
#include <ui/mat4.h>
+#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/OccupancyTracker.h>
@@ -65,7 +66,10 @@
#include "Effects/Daltonizer.h"
#include <map>
+#include <mutex>
+#include <queue>
#include <string>
+#include <utility>
namespace android {
@@ -413,7 +417,10 @@
Region& dirtyRegion, Region& opaqueRegion);
void preComposition(nsecs_t refreshStartTime);
- void postComposition();
+ void postComposition(nsecs_t refreshStartTime);
+ void updateCompositorTiming(
+ nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime);
void rebuildLayerStacks();
void setUpHWComposer();
void doComposition();
@@ -434,12 +441,13 @@
/* ------------------------------------------------------------------------
* VSync
*/
- void enableHardwareVsync();
- void resyncToHardwareVsync(bool makeAvailable);
- void disableHardwareVsync(bool makeUnavailable);
+ void enableHardwareVsync();
+ void resyncToHardwareVsync(bool makeAvailable);
+ void disableHardwareVsync(bool makeUnavailable);
public:
- void resyncWithRateLimit();
+ void resyncWithRateLimit();
+ void getCompositorTiming(CompositorTiming* compositorTiming);
private:
/* ------------------------------------------------------------------------
@@ -581,6 +589,17 @@
bool mPrimaryHWVsyncEnabled;
bool mHWVsyncAvailable;
+ // protected by mCompositorTimingLock;
+ mutable std::mutex mCompositeTimingLock;
+ CompositorTiming mCompositorTiming;
+
+ // Only accessed from the main thread.
+ struct CompositePresentTime {
+ nsecs_t composite { -1 };
+ std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
+ };
+ std::queue<CompositePresentTime> mCompositePresentTimes;
+
/* ------------------------------------------------------------------------
* Feature prototyping
*/
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 40a27e8..477eb27 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1036,6 +1036,11 @@
}
}
+void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
+ std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+ *compositorTiming = mCompositorTiming;
+}
+
void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
if (mEventThread == NULL) {
// This is a temporary workaround for b/7145521. A non-null pointer
@@ -1114,7 +1119,7 @@
setUpHWComposer();
doDebugFlashRegions();
doComposition();
- postComposition();
+ postComposition(refreshStartTime);
}
void SurfaceFlinger::doDebugFlashRegions()
@@ -1171,7 +1176,61 @@
}
}
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::updateCompositorTiming(
+ nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime) {
+ // Update queue of past composite+present times and determine the
+ // most recently known composite to present latency.
+ mCompositePresentTimes.push({compositeTime, presentFenceTime});
+ nsecs_t compositeToPresentLatency = -1;
+ while (!mCompositePresentTimes.empty()) {
+ CompositePresentTime& cpt = mCompositePresentTimes.front();
+ // Cached values should have been updated before calling this method,
+ // which helps avoid duplicate syscalls.
+ nsecs_t displayTime = cpt.display->getCachedSignalTime();
+ if (displayTime == Fence::SIGNAL_TIME_PENDING) {
+ break;
+ }
+ compositeToPresentLatency = displayTime - cpt.composite;
+ mCompositePresentTimes.pop();
+ }
+
+ // Don't let mCompositePresentTimes grow unbounded, just in case.
+ while (mCompositePresentTimes.size() > 16) {
+ mCompositePresentTimes.pop();
+ }
+
+ // Integer division and modulo round toward 0 not -inf, so we need to
+ // treat negative and positive offsets differently.
+ nsecs_t idealLatency = (sfVsyncPhaseOffsetNs >= 0) ?
+ (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
+ ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+
+ // Snap the latency to a value that removes scheduling jitter from the
+ // composition and present times, which often have >1ms of jitter.
+ // Reducing jitter is important if an app attempts to extrapolate
+ // something (such as user input) to an accurate diasplay time.
+ // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+ // with (presentLatency % interval).
+ nsecs_t snappedCompositeToPresentLatency = -1;
+ if (compositeToPresentLatency >= 0) {
+ nsecs_t bias = vsyncInterval / 2;
+ int64_t extraVsyncs =
+ (compositeToPresentLatency - idealLatency + bias) /
+ vsyncInterval;
+ nsecs_t extraLatency = extraVsyncs * vsyncInterval;
+ snappedCompositeToPresentLatency = idealLatency + extraLatency;
+ }
+
+ std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+ mCompositorTiming.deadline = vsyncPhase - idealLatency;
+ mCompositorTiming.interval = vsyncInterval;
+ if (snappedCompositeToPresentLatency >= 0) {
+ mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+ }
+}
+
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
{
const HWComposer& hwc = getHwComposer();
const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
@@ -1192,10 +1251,18 @@
mDisplayTimeline.push(retireFenceTime);
mDisplayTimeline.updateSignalTimes();
+ nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
+ nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+
+ // We use the refreshStartTime which might be sampled a little later than
+ // when we started doing work for this frame, but that should be okay
+ // since updateCompositorTiming has snapping logic.
+ updateCompositorTiming(
+ vsyncPhase, vsyncInterval, refreshStartTime, retireFenceTime);
+
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
- presentFenceTime, retireFenceTime);
-
+ presentFenceTime, retireFenceTime, mCompositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
diff --git a/services/vr/sensord/Android.mk b/services/vr/sensord/Android.mk
index 36d8400..e213bd6 100644
--- a/services/vr/sensord/Android.mk
+++ b/services/vr/sensord/Android.mk
@@ -46,21 +46,10 @@
cFlags := -DLOG_TAG=\"sensord\" \
-DTRACE=0
-ifeq ($(TARGET_USES_QCOM_BSP), true)
-ifneq ($(TARGET_QCOM_DISPLAY_VARIANT),)
- platform := .
-else
- platform := $(TARGET_BOARD_PLATFORM)
-endif
- cFlags += -DQCOM_B_FAMILY \
- -DQCOM_BSP
-endif
-
include $(CLEAR_VARS)
# Don't strip symbols so we see stack traces in logcat.
LOCAL_STRIP_MODULE := false
LOCAL_SRC_FILES := $(sourceFiles)
-PLATFORM := $(platform)
LOCAL_CFLAGS := $(cFlags)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a23056c..32f777d 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -739,10 +739,8 @@
const InstanceData& data = GetData(physicalDevice);
static const std::array<VkExtensionProperties, 2> loader_extensions = {{
// WSI extensions
-#if 0 // Remove this "#if 0" once the VK_KHR_incremental_present extension is ratified
{VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION},
-#endif
{VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION},
}};
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index c11d20f..9630ac9 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -20,7 +20,7 @@
#include <gui/BufferQueue.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
-#include <utils/SortedVector.h>
+#include <utils/Vector.h>
#include "driver.h"
@@ -108,19 +108,11 @@
class TimingInfo {
public:
- TimingInfo()
- : vals_{0, 0, 0, 0, 0},
- timestamp_desired_present_time_(0),
- timestamp_actual_present_time_(0),
- timestamp_render_complete_time_(0),
- timestamp_composition_latch_time_(0) {}
- TimingInfo(const VkPresentTimeGOOGLE* qp)
+ TimingInfo() = default;
+ TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId)
: vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
- timestamp_desired_present_time_(0),
- timestamp_actual_present_time_(0),
- timestamp_render_complete_time_(0),
- timestamp_composition_latch_time_(0) {}
- bool ready() {
+ native_frame_id_(nativeFrameId) {}
+ bool ready() const {
return (timestamp_desired_present_time_ &&
timestamp_actual_present_time_ &&
timestamp_render_complete_time_ &&
@@ -148,27 +140,20 @@
vals_.earliestPresentTime = early_time;
vals_.presentMargin = margin;
}
- void get_values(VkPastPresentationTimingGOOGLE* values) { *values = vals_; }
+ void get_values(VkPastPresentationTimingGOOGLE* values) const {
+ *values = vals_;
+ }
public:
- VkPastPresentationTimingGOOGLE vals_;
+ VkPastPresentationTimingGOOGLE vals_ { 0, 0, 0, 0, 0 };
- uint64_t timestamp_desired_present_time_;
- uint64_t timestamp_actual_present_time_;
- uint64_t timestamp_render_complete_time_;
- uint64_t timestamp_composition_latch_time_;
+ uint64_t native_frame_id_ { 0 };
+ uint64_t timestamp_desired_present_time_ { 0 };
+ uint64_t timestamp_actual_present_time_ { 0 };
+ uint64_t timestamp_render_complete_time_ { 0 };
+ uint64_t timestamp_composition_latch_time_ { 0 };
};
-static inline int compare_type(const TimingInfo& lhs, const TimingInfo& rhs) {
- // TODO(ianelliott): Change this from presentID to the frame ID once
- // brianderson lands the appropriate patch:
- if (lhs.vals_.presentID < rhs.vals_.presentID)
- return -1;
- if (lhs.vals_.presentID > rhs.vals_.presentID)
- return 1;
- return 0;
-}
-
// ----------------------------------------------------------------------------
struct Surface {
@@ -191,11 +176,13 @@
enum { MIN_NUM_FRAMES_AGO = 5 };
struct Swapchain {
- Swapchain(Surface& surface_, uint32_t num_images_)
+ Swapchain(Surface& surface_,
+ uint32_t num_images_,
+ VkPresentModeKHR present_mode)
: surface(surface_),
num_images(num_images_),
+ mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
frame_timestamps_enabled(false) {
- timing.clear();
ANativeWindow* window = surface.window.get();
int64_t rdur;
native_window_get_refresh_cycle_duration(
@@ -206,6 +193,7 @@
Surface& surface;
uint32_t num_images;
+ bool mailbox_mode;
bool frame_timestamps_enabled;
uint64_t refresh_duration;
@@ -221,7 +209,7 @@
bool dequeued;
} images[android::BufferQueue::NUM_BUFFER_SLOTS];
- android::SortedVector<TimingInfo> timing;
+ android::Vector<TimingInfo> timing;
};
VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
@@ -293,73 +281,64 @@
}
uint32_t get_num_ready_timings(Swapchain& swapchain) {
- uint32_t num_ready = 0;
- uint32_t num_timings = static_cast<uint32_t>(swapchain.timing.size());
- uint32_t frames_ago = num_timings;
- for (uint32_t i = 0; i < num_timings; i++) {
- TimingInfo* ti = &swapchain.timing.editItemAt(i);
- if (ti) {
- if (ti->ready()) {
- // This TimingInfo is ready to be reported to the user. Add it
- // to the num_ready.
- num_ready++;
- } else {
- // This TimingInfo is not yet ready to be reported to the user,
- // and so we should look for any available timestamps that
- // might make it ready.
- int64_t desired_present_time = 0;
- int64_t render_complete_time = 0;
- int64_t composition_latch_time = 0;
- int64_t actual_present_time = 0;
- for (uint32_t f = MIN_NUM_FRAMES_AGO; f < frames_ago; f++) {
- // Obtain timestamps:
- int ret = native_window_get_frame_timestamps(
- swapchain.surface.window.get(), f,
- &desired_present_time, &render_complete_time,
- &composition_latch_time,
- NULL, //&first_composition_start_time,
- NULL, //&last_composition_start_time,
- NULL, //&composition_finish_time,
- // TODO(ianelliott): Maybe ask if this one is
- // supported, at startup time (since it may not be
- // supported):
- &actual_present_time,
- NULL, //&display_retire_time,
- NULL, //&dequeue_ready_time,
- NULL /*&reads_done_time*/);
- if (ret) {
- break;
- } else if (!ret) {
- // We obtained at least one valid timestamp. See if it
- // is for the present represented by this TimingInfo:
- if (static_cast<uint64_t>(desired_present_time) ==
- ti->vals_.desiredPresentTime) {
- // Record the timestamp(s) we received, and then
- // see if this TimingInfo is ready to be reported
- // to the user:
- ti->timestamp_desired_present_time_ =
- static_cast<uint64_t>(desired_present_time);
- ti->timestamp_actual_present_time_ =
- static_cast<uint64_t>(actual_present_time);
- ti->timestamp_render_complete_time_ =
- static_cast<uint64_t>(render_complete_time);
- ti->timestamp_composition_latch_time_ =
- static_cast<uint64_t>(composition_latch_time);
+ if (swapchain.timing.size() < MIN_NUM_FRAMES_AGO) {
+ return 0;
+ }
- if (ti->ready()) {
- // The TimingInfo has received enough
- // timestamps, and should now use those
- // timestamps to calculate the info that should
- // be reported to the user:
- //
- ti->calculate(swapchain.refresh_duration);
- num_ready++;
- }
- break;
- }
- }
- }
- }
+ uint32_t num_ready = 0;
+ const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1;
+ for (uint32_t i = 0; i < num_timings; i++) {
+ TimingInfo& ti = swapchain.timing.editItemAt(i);
+ if (ti.ready()) {
+ // This TimingInfo is ready to be reported to the user. Add it
+ // to the num_ready.
+ num_ready++;
+ continue;
+ }
+ // This TimingInfo is not yet ready to be reported to the user,
+ // and so we should look for any available timestamps that
+ // might make it ready.
+ int64_t desired_present_time = 0;
+ int64_t render_complete_time = 0;
+ int64_t composition_latch_time = 0;
+ int64_t actual_present_time = 0;
+ // Obtain timestamps:
+ int ret = native_window_get_frame_timestamps(
+ swapchain.surface.window.get(), ti.native_frame_id_,
+ &desired_present_time, &render_complete_time,
+ &composition_latch_time,
+ NULL, //&first_composition_start_time,
+ NULL, //&last_composition_start_time,
+ NULL, //&composition_finish_time,
+ // TODO(ianelliott): Maybe ask if this one is
+ // supported, at startup time (since it may not be
+ // supported):
+ &actual_present_time,
+ NULL, //&display_retire_time,
+ NULL, //&dequeue_ready_time,
+ NULL /*&reads_done_time*/);
+
+ if (ret != android::NO_ERROR) {
+ continue;
+ }
+
+ // Record the timestamp(s) we received, and then see if this TimingInfo
+ // is ready to be reported to the user:
+ ti.timestamp_desired_present_time_ =
+ static_cast<uint64_t>(desired_present_time);
+ ti.timestamp_actual_present_time_ =
+ static_cast<uint64_t>(actual_present_time);
+ ti.timestamp_render_complete_time_ =
+ static_cast<uint64_t>(render_complete_time);
+ ti.timestamp_composition_latch_time_ =
+ static_cast<uint64_t>(composition_latch_time);
+
+ if (ti.ready()) {
+ // The TimingInfo has received enough timestamps, and should now
+ // use those timestamps to calculate the info that should be
+ // reported to the user:
+ ti.calculate(swapchain.refresh_duration);
+ num_ready++;
}
}
return num_ready;
@@ -369,29 +348,35 @@
void copy_ready_timings(Swapchain& swapchain,
uint32_t* count,
VkPastPresentationTimingGOOGLE* timings) {
- uint32_t num_copied = 0;
- uint32_t num_timings = static_cast<uint32_t>(swapchain.timing.size());
- if (*count < num_timings) {
- num_timings = *count;
+ if (swapchain.timing.empty()) {
+ *count = 0;
+ return;
}
- for (uint32_t i = 0; i < num_timings; i++) {
- TimingInfo* ti = &swapchain.timing.editItemAt(i);
- if (ti && ti->ready()) {
- ti->get_values(&timings[num_copied]);
- num_copied++;
- // We only report the values for a given present once, so remove
- // them from swapchain.timing:
- //
- // TODO(ianelliott): SEE WHAT HAPPENS TO THE LOOP WHEN THE
- // FOLLOWING IS DONE:
- swapchain.timing.removeAt(i);
- i--;
- num_timings--;
- if (*count == num_copied) {
- break;
- }
+
+ size_t last_ready = swapchain.timing.size() - 1;
+ while (!swapchain.timing[last_ready].ready()) {
+ if (last_ready == 0) {
+ *count = 0;
+ return;
}
+ last_ready--;
}
+
+ uint32_t num_copied = 0;
+ size_t num_to_remove = 0;
+ for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) {
+ const TimingInfo& ti = swapchain.timing[i];
+ if (ti.ready()) {
+ ti.get_values(&timings[num_copied]);
+ num_copied++;
+ }
+ num_to_remove++;
+ }
+
+ // Discard old frames that aren't ready if newer frames are ready.
+ // We don't expect to get the timing info for those old frames.
+ swapchain.timing.removeItemsAt(0, num_to_remove);
+
*count = num_copied;
}
@@ -877,7 +862,8 @@
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!mem)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
+ Swapchain* swapchain =
+ new (mem) Swapchain(surface, num_images, create_info->presentMode);
// -- Dequeue all buffers and create a VkImage for each --
// Any failures during or after this must cancel the dequeued buffers.
@@ -1179,7 +1165,8 @@
*SwapchainFromHandle(present_info->pSwapchains[sc]);
uint32_t image_idx = present_info->pImageIndices[sc];
Swapchain::Image& img = swapchain.images[image_idx];
- const VkPresentRegionKHR* region = (regions) ? ®ions[sc] : nullptr;
+ const VkPresentRegionKHR* region =
+ (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr;
const VkPresentTimeGOOGLE* time = (times) ? ×[sc] : nullptr;
VkResult swapchain_result = VK_SUCCESS;
VkResult result;
@@ -1245,13 +1232,20 @@
native_window_enable_frame_timestamps(window, true);
swapchain.frame_timestamps_enabled = true;
}
- // Record this presentID and desiredPresentTime so it can
- // be later correlated to this present.
- TimingInfo timing_record(time);
- swapchain.timing.add(timing_record);
- uint32_t num_timings =
- static_cast<uint32_t>(swapchain.timing.size());
- if (num_timings > MAX_TIMING_INFOS) {
+
+ // Record the nativeFrameId so it can be later correlated to
+ // this present.
+ uint64_t nativeFrameId = 0;
+ err = native_window_get_next_frame_id(
+ window, &nativeFrameId);
+ if (err != android::NO_ERROR) {
+ ALOGE("Failed to get next native frame ID.");
+ }
+
+ // Add a new timing record with the user's presentID and
+ // the nativeFrameId.
+ swapchain.timing.push_back(TimingInfo(time, nativeFrameId));
+ while (swapchain.timing.size() > MAX_TIMING_INFOS) {
swapchain.timing.removeAt(0);
}
if (time->desiredPresentTime) {