Merge "Remove magic number usage in SurfaceFlinger"
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index efc050b..d1e94ed 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -103,8 +103,7 @@
LOCAL_MODULE := dumpstate
-LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES) \
- android.hardware.vibrator@1.0
+LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES)
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 67172b6..b323624 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -42,7 +42,6 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
-#include <android/hardware/vibrator/1.0/IVibrator.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <openssl/sha.h>
@@ -54,8 +53,6 @@
#include "dumpstate.h"
using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
-using ::android::hardware::vibrator::V1_0::IVibrator;
-using VibratorStatus = ::android::hardware::vibrator::V1_0::Status;
// TODO: remove once moved to namespace
using android::os::dumpstate::CommandOptions;
@@ -1363,6 +1360,16 @@
.Build());
}
+static void Vibrate(int duration_ms) {
+ // clang-format off
+ RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
+ CommandOptions::WithTimeout(10)
+ .Log("Vibrate: '%s'\n")
+ .Always()
+ .Build());
+ // clang-format on
+}
+
int main(int argc, char *argv[]) {
int do_add_date = 0;
int do_zip_file = 0;
@@ -1608,22 +1615,8 @@
fclose(cmdline);
}
- ::android::sp<IVibrator> vibrator = nullptr;
if (do_vibrate) {
- vibrator = IVibrator::getService();
-
- if (vibrator != nullptr) {
- // cancel previous vibration if any
- ::android::hardware::Return<VibratorStatus> offStatus = vibrator->off();
- if (!offStatus.isOk() || offStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator off failed.");
- } else {
- ::android::hardware::Return<VibratorStatus> onStatus = vibrator->on(150);
- if (!onStatus.isOk() || onStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator on failed.");
- }
- }
- }
+ Vibrate(150);
}
if (do_fb && ds.do_early_screenshot_) {
@@ -1803,21 +1796,9 @@
}
/* vibrate a few but shortly times to let user know it's finished */
- if (vibrator != nullptr) {
- // in case dumpstate magically completes before the above vibration
- ::android::hardware::Return<VibratorStatus> offStatus = vibrator->off();
- if (!offStatus.isOk() || offStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator off failed.");
- } else {
- for (int i = 0; i < 3; i++) {
- ::android::hardware::Return<VibratorStatus> onStatus = vibrator->on(75);
- if (!onStatus.isOk() || onStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator on failed.");
- break;
- }
- usleep((75 + 50) * 1000);
- }
- }
+ for (int i = 0; i < 3; i++) {
+ Vibrate(75);
+ usleep((75 + 50) * 1000);
}
/* tell activity manager we're done */
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index c5ae9d2..3476964 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -15,8 +15,6 @@
"libutils",
"liblog",
"libbinder",
- "android.hidl.manager@1.0",
- "libhidlbase"
],
clang: true,
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 860b7b4..f0e7200 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -45,7 +45,8 @@
using android::base::unique_fd;
using android::base::WriteFully;
-static int sort_func(const String16* lhs, const String16* rhs) {
+static int sort_func(const String16* lhs, const String16* rhs)
+{
return lhs->compare(*rhs);
}
@@ -54,11 +55,10 @@
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--help | --hw | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+ " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
- " --hw: list all hw services running on the device\n"
" --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
@@ -72,42 +72,16 @@
return false;
}
-static void ListHardwareServices(android::hidl::manager::V1_0::IServiceManager* hm) {
- using android::hardware::hidl_vec;
- using android::hardware::hidl_string;
- using android::hardware::Return;
- using android::sp;
-
- if (hm == nullptr) {
- ALOGE("Unable to get hardware service manager!");
- aerr << "Failed to get hardware service manager!";
- return;
- }
-
- Return<void> ret = hm->list([](const hidl_vec<hidl_string> ®istered){
- aout << "Currently running hardware services:" << endl;
- for (const auto &service : registered) {
- aout << " " << service << endl;
- }
- });
-
- if (!ret.isOk()) {
- aerr << "Failed to list hardware services: " << ret.description();
- }
-}
-
int Dumpsys::main(int argc, char* const argv[]) {
Vector<String16> services;
Vector<String16> args;
Vector<String16> skippedServices;
bool showListOnly = false;
- bool listHwOnly = false;
bool skipServices = false;
int timeoutArg = 10;
static struct option longOptions[] = {
{"skip", no_argument, 0, 0 },
{"help", no_argument, 0, 0 },
- {"hw", no_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
@@ -131,8 +105,6 @@
} else if (!strcmp(longOptions[optionIndex].name, "help")) {
usage();
return 0;
- } else if (!strcmp(longOptions[optionIndex].name, "hw")) {
- listHwOnly = true;
}
break;
@@ -171,17 +143,11 @@
}
if ((skipServices && skippedServices.empty()) ||
- (showListOnly && (!services.empty() || !skippedServices.empty())) ||
- (listHwOnly && (skipServices || services.size() > 0 || showListOnly))) {
+ (showListOnly && (!services.empty() || !skippedServices.empty()))) {
usage();
return -1;
}
- if (listHwOnly) {
- ListHardwareServices(hm_);
- return 0;
- }
-
if (services.empty() || showListOnly) {
// gets all services
services = sm_->listServices();
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 20d515d..2534dde 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -17,21 +17,18 @@
#ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
#define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
-#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/IServiceManager.h>
namespace android {
class Dumpsys {
public:
- Dumpsys(android::IServiceManager* sm,
- android::hidl::manager::V1_0::IServiceManager* hm) : sm_(sm), hm_(hm) {
+ Dumpsys(android::IServiceManager* sm) : sm_(sm) {
}
int main(int argc, char* const argv[]);
private:
android::IServiceManager* sm_;
- android::hidl::manager::V1_0::IServiceManager* hm_;
};
}
diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp
index b180c98..8ba0eba 100644
--- a/cmds/dumpsys/main.cpp
+++ b/cmds/dumpsys/main.cpp
@@ -27,7 +27,6 @@
#include <stdio.h>
using namespace android;
-using HServiceManager = android::hidl::manager::V1_0::IServiceManager;
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
@@ -39,8 +38,6 @@
return 20;
}
- sp<HServiceManager> hm = HServiceManager::getService("manager");
-
- Dumpsys dumpsys(sm.get(), hm.get());
+ Dumpsys dumpsys(sm.get());
return dumpsys.main(argc, argv);
}
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index e00444f..7698ed5 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -5,12 +5,8 @@
srcs: ["dumpsys_test.cpp"],
shared_libs: [
- "android.hidl.manager@1.0",
"libbase",
"libbinder",
- "liblog",
- "libhidlbase",
- "libhidltransport",
"libutils",
],
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 01a2fa3..a61cb00 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -44,12 +44,6 @@
using ::testing::internal::GetCapturedStderr;
using ::testing::internal::GetCapturedStdout;
-using android::hardware::hidl_vec;
-using android::hardware::hidl_string;
-using android::hardware::Void;
-using HServiceManager = android::hidl::manager::V1_0::IServiceManager;
-using IServiceNotification = android::hidl::manager::V1_0::IServiceNotification;
-
class ServiceManagerMock : public IServiceManager {
public:
MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
@@ -61,27 +55,6 @@
MOCK_METHOD0(onAsBinder, IBinder*());
};
-class HardwareServiceManagerMock : public HServiceManager {
- public:
- template<typename T>
- using R = android::hardware::Return<T>; // conflicts with ::testing::Return
-
- MOCK_METHOD2(get, R<sp<IBase>>(const hidl_string&, const hidl_string&));
- MOCK_METHOD3(add,
- R<bool>(const hidl_vec<hidl_string>&,
- const hidl_string&,
- const sp<IBase>&));
- MOCK_METHOD1(list, R<void>(list_cb));
- MOCK_METHOD2(listByInterface,
- R<void>(const hidl_string&, listByInterface_cb));
- MOCK_METHOD3(registerForNotifications,
- R<bool>(const hidl_string&,
- const hidl_string&,
- const sp<IServiceNotification>&));
- MOCK_METHOD1(debugDump, R<void>(debugDump_cb));
-
-};
-
class BinderMock : public BBinder {
public:
BinderMock() {
@@ -111,26 +84,6 @@
return MakeAction(new WriteOnFdAction(output));
}
-// gmock black magic to provide a WithArg<0>(List(services)) matcher
-typedef void HardwareListFunction(HServiceManager::list_cb);
-
-class HardwareListAction : public ActionInterface<HardwareListFunction> {
- public:
- explicit HardwareListAction(const hidl_vec<hidl_string> &services) : services_(services) {
- }
- virtual Result Perform(const ArgumentTuple& args) {
- auto cb = ::std::tr1::get<0>(args);
- cb(services_);
- }
-
- private:
- hidl_vec<hidl_string> services_;
-};
-
-Action<HardwareListFunction> HardwareList(const hidl_vec<hidl_string> &services) {
- return MakeAction(new HardwareListAction(services));
-}
-
// Matcher for args using Android's Vector<String16> format
// TODO: move it to some common testing library
MATCHER_P(AndroidElementsAre, expected, "") {
@@ -168,7 +121,7 @@
class DumpsysTest : public Test {
public:
- DumpsysTest() : sm_(), hm_(), dump_(&sm_, &hm_), stdout_(), stderr_() {
+ DumpsysTest() : sm_(), dump_(&sm_), stdout_(), stderr_() {
}
void ExpectListServices(std::vector<std::string> services) {
@@ -176,22 +129,9 @@
for (auto& service : services) {
services16.add(String16(service.c_str()));
}
-
EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
}
- void ExpectListHardwareServices(std::vector<std::string> services) {
- hidl_vec<hidl_string> hidl_services;
- hidl_services.resize(services.size());
- for (size_t i = 0; i < services.size(); i++) {
- hidl_services[i] = services[i];
- }
-
- EXPECT_CALL(hm_, list(_)).WillRepeatedly(DoAll(
- WithArg<0>(HardwareList(hidl_services)),
- Return(Void())));
- }
-
sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
sp<BinderMock> binder_mock;
if (running) {
@@ -235,10 +175,8 @@
EXPECT_THAT(status, Eq(0));
}
- void AssertRunningServices(const std::vector<std::string>& services,
- const std::string &message = "Currently running services:") {
- std::string expected(message);
- expected.append("\n");
+ void AssertRunningServices(const std::vector<std::string>& services) {
+ std::string expected("Currently running services:\n");
for (const std::string& service : services) {
expected.append(" ").append(service).append("\n");
}
@@ -266,21 +204,12 @@
}
ServiceManagerMock sm_;
- HardwareServiceManagerMock hm_;
Dumpsys dump_;
private:
std::string stdout_, stderr_;
};
-TEST_F(DumpsysTest, ListHwServices) {
- ExpectListHardwareServices({"Locksmith", "Valet"});
-
- CallMain({"--hw"});
-
- AssertRunningServices({"Locksmith", "Valet"}, "Currently running hardware services:");
-}
-
// Tests 'dumpsys -l' when all services are running
TEST_F(DumpsysTest, ListAllServices) {
ExpectListServices({"Locksmith", "Valet"});
diff --git a/cmds/lshal/lshal.cpp b/cmds/lshal/lshal.cpp
index bc5eaf2..9998a46 100644
--- a/cmds/lshal/lshal.cpp
+++ b/cmds/lshal/lshal.cpp
@@ -28,31 +28,60 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-template <typename A, typename B, typename C, typename D, typename E>
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+template <typename A, typename B, typename C, typename D, typename E, typename F>
void printColumn(std::stringstream &stream,
- const A &a, const B &b, const C &c, const D &d, const E &e) {
+ const A &a, const B &b, const C &c, const D &d, const E &, const F &f) {
using namespace ::std;
stream << left
<< setw(70) << a << "\t"
<< setw(20) << b << "\t"
<< setw(10) << c << "\t"
<< setw(5) << d << "\t"
- << setw(0) << e
+ // TODO(b/34984175): enable selecting columns
+ // << setw(16) << e << "\t"
+ << setw(0) << f
<< endl;
}
+template <typename A>
+std::string join(const A &components, const std::string &separator) {
+ std::stringstream out;
+ bool first = true;
+ for (const auto &component : components) {
+ if (!first) {
+ out << separator;
+ }
+ out << component;
+
+ first = false;
+ }
+ return out.str();
+}
+
std::string toHexString(uint64_t t) {
std::ostringstream os;
os << std::hex << std::setfill('0') << std::setw(16) << t;
return os.str();
}
-::android::status_t getReferencedPids(
+std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) {
+ const char *pos = strchr(s.c_str(), c);
+ if (pos == nullptr) {
+ return {s, {}};
+ }
+ return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)};
+}
+
+bool getReferencedPids(
pid_t serverPid, std::map<uint64_t, std::string> *objects) {
std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
if (!ifs.is_open()) {
- return ::android::PERMISSION_DENIED;
+ return false;
}
static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
@@ -77,66 +106,165 @@
(*objects)[ptr] += line.substr(pos + proc.size());
}
}
- return ::android::OK;
+ return true;
}
+void dumpAllLibraries(std::stringstream &stream, const std::string &mode,
+ const sp<IServiceManager> &manager) {
+ using namespace ::std;
+ using namespace ::android::hardware;
+ using namespace ::android::hidl::manager::V1_0;
+ using namespace ::android::hidl::base::V1_0;
+ auto ret = manager->list([&] (const auto &fqInstanceNames) {
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = split(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ printColumn(stream,
+ serviceName,
+ instanceName,
+ mode,
+ "N/A",
+ "N/A",
+ "N/A");
+ }
+ });
+ if (!ret.isOk()) {
+ cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ << ret.description() << endl;
+ }
+}
+
+void dumpPassthrough(std::stringstream &stream, const std::string &mode,
+ const sp<IServiceManager> &manager) {
+ using namespace ::std;
+ using namespace ::android::hardware;
+ using namespace ::android::hidl::manager::V1_0;
+ using namespace ::android::hidl::base::V1_0;
+ auto ret = manager->debugDump([&] (const auto &infos) {
+ for (const auto &info : infos) {
+
+ printColumn(stream,
+ info.interfaceName,
+ info.instanceName,
+ mode,
+ info.clientPids.size() == 1 ? std::to_string(info.clientPids[0]) : "N/A",
+ "N/A",
+ join(info.clientPids, " "));
+ }
+ });
+ if (!ret.isOk()) {
+ cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ << ret.description() << endl;
+ }
+}
+
+void dumpBinderized(std::stringstream &stream, const std::string &mode,
+ const sp<IServiceManager> &manager) {
+ using namespace ::std;
+ using namespace ::android::hardware;
+ using namespace ::android::hidl::manager::V1_0;
+ using namespace ::android::hidl::base::V1_0;
+ auto listRet = manager->list([&] (const auto &fqInstanceNames) {
+ // server pid, .ptr value of binder object, child pids
+ std::map<std::string, DebugInfo> allDebugInfos;
+ std::map<pid_t, std::map<uint64_t, std::string>> allPids;
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = split(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto getRet = manager->get(serviceName, instanceName);
+ if (!getRet.isOk()) {
+ cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "cannot be fetched from service manager:"
+ << getRet.description() << endl;
+ continue;
+ }
+ sp<IBase> service = getRet;
+ if (service == nullptr) {
+ cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "cannot be fetched from service manager (null)";
+ continue;
+ }
+ auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) {
+ allDebugInfos[fqInstanceName] = debugInfo;
+ if (debugInfo.pid >= 0) {
+ allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+ }
+ });
+ if (!debugRet.isOk()) {
+ cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "debugging information cannot be retrieved:"
+ << debugRet.description() << endl;
+ }
+ }
+ for (auto &pair : allPids) {
+ pid_t serverPid = pair.first;
+ if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+ std::cerr << "Warning: no information for PID " << serverPid
+ << ", are you root?" << std::endl;
+ }
+ }
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = split(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto it = allDebugInfos.find(fqInstanceName);
+ if (it == allDebugInfos.end()) {
+ printColumn(stream,
+ serviceName,
+ instanceName,
+ mode,
+ "N/A",
+ "N/A",
+ ""
+ );
+ continue;
+ }
+ const DebugInfo &info = it->second;
+ printColumn(stream,
+ serviceName,
+ instanceName,
+ mode,
+ info.pid < 0 ? "N/A" : std::to_string(info.pid),
+ info.ptr == 0 ? "N/A" : toHexString(info.ptr),
+ info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]
+ );
+ }
+
+ });
+ if (!listRet.isOk()) {
+ cerr << "Error: Failed to list services for " << mode << ": "
+ << listRet.description() << endl;
+ }
+}
int dump() {
using namespace ::std;
using namespace ::android::hardware;
- using namespace ::android::hidl::manager::V1_0;
-
- std::map<std::string, ::android::sp<IServiceManager>> mapping = {
- {"hwbinder", defaultServiceManager()},
- {"passthrough", getPassthroughServiceManager()}
- };
std::stringstream stream;
stream << "All services:" << endl;
stream << left;
- printColumn(stream, "Interface", "Instance", "Transport", "Server", "Clients");
+ printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients");
- for (const auto &pair : mapping) {
- const std::string &mode = pair.first;
- const ::android::sp<IServiceManager> &manager = pair.second;
-
- if (manager == nullptr) {
- cerr << "Failed to get IServiceManager for " << mode << "!" << endl;
- continue;
- }
-
- auto ret = manager->debugDump([&](const auto ®istered) {
- // server pid, .ptr value of binder object, child pids
- std::map<pid_t, std::map<uint64_t, std::string>> allPids;
- for (const auto &info : registered) {
- if (info.pid < 0) {
- continue;
- }
- pid_t serverPid = info.pid;
- allPids[serverPid].clear();
- }
- for (auto &pair : allPids) {
- pid_t serverPid = pair.first;
- if (getReferencedPids(serverPid, &allPids[serverPid]) != ::android::OK) {
- std::cerr << "Warning: no information for PID " << serverPid
- << ", are you root?" << std::endl;
- }
- }
- for (const auto &info : registered) {
- printColumn(stream,
- info.interfaceName,
- info.instanceName.empty() ? "N/A" : info.instanceName,
- mode,
- info.pid < 0 ? "N/A" : std::to_string(info.pid),
- info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]);
- }
- });
- if (!ret.isOk()) {
- cerr << "Failed to list services for " << mode << ": "
- << ret.description() << endl;
- }
+ auto bManager = defaultServiceManager();
+ if (bManager == nullptr) {
+ cerr << "Failed to get defaultServiceManager()!" << endl;
+ } else {
+ dumpBinderized(stream, "hwbinder", bManager);
+ // Passthrough PIDs are registered to the binderized manager as well.
+ dumpPassthrough(stream, "passthrough", bManager);
}
+
+ auto pManager = getPassthroughServiceManager();
+ if (pManager == nullptr) {
+ cerr << "Failed to get getPassthroughServiceManager()!" << endl;
+ } else {
+ dumpAllLibraries(stream, "passthrough", pManager);
+ }
+
cout << stream.rdbuf();
return 0;
}
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index c3014b2..966e70d 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -204,6 +204,7 @@
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSharedBufferMode(va_list args);
int dispatchSetAutoRefresh(va_list args);
+ int dispatchGetNextFrameId(va_list args);
int dispatchEnableFrameTimestamps(va_list args);
int dispatchGetFrameTimestamps(va_list args);
int dispatchGetDisplayRefreshCycleDuration(va_list args);
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index 8e93f72..001769f 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -39,7 +39,9 @@
public:
static inline GraphicBufferMapper& get() { return getInstance(); }
+ // This may NOT work on devices without a valid Gralloc2::Mapper.
status_t registerBuffer(buffer_handle_t handle);
+
status_t registerBuffer(const GraphicBuffer* buffer);
status_t unregisterBuffer(buffer_handle_t handle);
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..d1f9f6a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -831,6 +831,9 @@
case NATIVE_WINDOW_SET_AUTO_REFRESH:
res = dispatchSetAutoRefresh(args);
break;
+ case NATIVE_WINDOW_GET_NEXT_FRAME_ID:
+ res = dispatchGetNextFrameId(args);
+ break;
case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS:
res = dispatchEnableFrameTimestamps(args);
break;
@@ -960,6 +963,12 @@
return setAutoRefresh(autoRefresh);
}
+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);
@@ -967,7 +976,7 @@
}
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,7 +987,7 @@
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,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 412c0f6..3f56665 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -598,8 +598,8 @@
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 +619,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;
@@ -748,6 +755,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,8 +770,7 @@
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);
}
@@ -778,6 +786,8 @@
EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
EXPECT_EQ(0, 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);
@@ -802,8 +812,7 @@
// 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);
+ int result = getAllFrameTimestamps(fId1);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
}
@@ -833,16 +842,17 @@
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.
+// 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 +863,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 +879,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 +901,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 +910,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 +922,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 +931,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 +939,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 +951,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 +969,7 @@
mFrames[0].signalQueueFences();
// Dequeue and queue frame 2.
+ const uint64_t fId2 = getNextFrameId();
dequeueAndQueue(1);
mFrames[1].signalQueueFences();
@@ -971,9 +980,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 +995,7 @@
mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
// Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
dequeueAndQueue(0);
mFrames[0].signalQueueFences();
@@ -1001,10 +1010,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 +1029,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 +1050,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 +1075,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 +1093,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 +1115,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 +1137,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 +1153,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 +1173,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 +1205,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/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b0ed2df..a3b6e18 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -63,7 +63,14 @@
if (mMapper->valid()) {
error = static_cast<gralloc1_error_t>(mMapper->retain(handle));
} else {
+ // This always returns GRALLOC1_BAD_HANDLE when handle is from a
+ // remote process and mDevice is backed by Gralloc1On0Adapter.
error = mDevice->retain(handle);
+ if (error == GRALLOC1_ERROR_BAD_HANDLE &&
+ mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ ALOGE("registerBuffer by handle is not supported with "
+ "Gralloc1On0Adapter");
+ }
}
ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
diff --git a/libs/vr/libvrflinger/Android.mk b/libs/vr/libvrflinger/Android.mk
index d90e85a..1706f30 100644
--- a/libs/vr/libvrflinger/Android.mk
+++ b/libs/vr/libvrflinger/Android.mk
@@ -77,11 +77,6 @@
LOCAL_CFLAGS += -DTRACE=0
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-ifeq ($(TARGET_USES_QCOM_BSP), true)
- LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
- LOCAL_C_INCLUDES += hardware/qcom/display/libqdutils
- LOCAL_SHARED_LIBRARIES += libqdutils
-endif
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_WHOLE_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_MODULE := libvrflinger
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index c464c98..5309acf 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -318,6 +318,10 @@
return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
+void DisplayService::OnHardwareComposerRefresh() {
+ hardware_composer_.OnHardwareComposerRefresh();
+}
+
void DisplayService::SetDisplayConfigurationUpdateNotifier(
DisplayConfigurationUpdateNotifier update_notifier) {
update_notifier_ = update_notifier;
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index ebd97de..5de4f1d 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -68,6 +68,8 @@
}
}
+ void OnHardwareComposerRefresh();
+
private:
friend BASE;
friend DisplaySurface;
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 5253b26..e6ed665 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1287,6 +1287,10 @@
// TODO(eieio): implement display hotplug callbacks.
}
+void HardwareComposer::OnHardwareComposerRefresh() {
+ // TODO(steventhomas): Handle refresh.
+}
+
void HardwareComposer::SetBacklightBrightness(int brightness) {
if (backlight_brightness_fd_) {
std::array<char, 32> text;
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 33f090d..b6aa807 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -224,6 +224,8 @@
Compositor* GetCompositor() { return &compositor_; }
+ void OnHardwareComposerRefresh();
+
private:
int32_t EnableVsync(bool enabled);
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 04c8363..17dce96 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -21,6 +21,7 @@
void EnterVrMode();
void ExitVrMode();
+ void OnHardwareComposerRefresh();
private:
std::thread displayd_thread_;
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 82ce067..9163e71 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -106,5 +106,13 @@
}
}
+void VrFlinger::OnHardwareComposerRefresh() {
+ if (display_service_) {
+ display_service_->OnHardwareComposerRefresh();
+ } else {
+ ALOGE("OnHardwareComposerRefresh failed : Display service is not started.");
+ }
+}
+
} // namespace dvr
} // namespace android
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 027c18d..6485ae5 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -643,10 +643,12 @@
#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
#define EGL_READS_DONE_TIME_ANDROID 0x3157
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(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 PFNEGLGETNEXTFRAMEIDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
#endif
#endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 2782ed7..2d02b72 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -216,6 +216,8 @@
(__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
// EGL_ANDROID_get_frame_timestamps
+ { "eglGetNextFrameIdANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID },
{ "eglGetFrameTimestampsANDROID",
(__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
{ "eglQueryTimestampSupportedANDROID",
@@ -2048,8 +2050,42 @@
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 eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
- EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
+ EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps,
EGLnsecsANDROID *values)
{
clearError();
@@ -2118,7 +2154,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,6 +2171,7 @@
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);
}
}
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index 7aa0d30..f24d634 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -57,9 +57,12 @@
New Procedures and Functions
+ EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR *frameId);
+
EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
- EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
- EGLnsecsANDROID *values);
+ EGLuint64KHR frameId, EGLint numTimestamps,
+ const EGLint *timestamps, EGLnsecsANDROID *values);
EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
surface, EGLint timestamp);
@@ -95,23 +98,31 @@
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 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
@@ -175,3 +186,6 @@
- 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.
diff --git a/opengl/specs/README b/opengl/specs/README
index 8a3a7aa..1853214 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.
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/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1c99036..d2b26c2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -60,9 +60,8 @@
// ---------------------------------------------------------------------------
-HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger, bool useVrComposer)
- : mFlinger(flinger),
- mAdapter(),
+HWComposer::HWComposer(bool useVrComposer)
+ : mAdapter(),
mHwcDevice(),
mDisplayData(2),
mFreeDisplaySlots(),
@@ -211,7 +210,7 @@
}
void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) {
- mFlinger->repaintEverything();
+ mEventHandler->onInvalidateReceived(this);
}
void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display,
@@ -257,7 +256,7 @@
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
- mEventHandler->onVSyncReceived(disp, timestamp);
+ mEventHandler->onVSyncReceived(this, disp, timestamp);
}
status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7b61e0e..0713709 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -64,15 +64,16 @@
class NativeHandle;
class Region;
class String8;
-class SurfaceFlinger;
class HWComposer
{
public:
class EventHandler {
friend class HWComposer;
- virtual void onVSyncReceived(int32_t disp, nsecs_t timestamp) = 0;
+ virtual void onVSyncReceived(
+ HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
virtual void onHotplugReceived(int32_t disp, bool connected) = 0;
+ virtual void onInvalidateReceived(HWComposer* composer) = 0;
protected:
virtual ~EventHandler() {}
};
@@ -80,7 +81,7 @@
// useVrComposer is passed to the composer HAL. When true, the composer HAL
// will use the vr composer service, otherwise it uses the real hardware
// composer.
- HWComposer(const sp<SurfaceFlinger>& flinger, bool useVrComposer);
+ HWComposer(bool useVrComposer);
~HWComposer();
@@ -211,7 +212,6 @@
HWC2::Vsync vsyncEnabled;
};
- sp<SurfaceFlinger> mFlinger;
std::unique_ptr<HWC2On1Adapter> mAdapter;
std::unique_ptr<HWC2::Device> mHwcDevice;
std::vector<DisplayData> mDisplayData;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index cc5578d..0bfc56e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -277,7 +277,7 @@
}
void HWComposer::invalidate() {
- mFlinger->repaintEverything();
+ mEventHandler.onInvalidateReceived(this);
}
void HWComposer::vsync(int disp, int64_t timestamp) {
@@ -302,7 +302,7 @@
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
- mEventHandler.onVSyncReceived(disp, timestamp);
+ mEventHandler.onVSyncReceived(this, disp, timestamp);
}
}
@@ -1318,7 +1318,7 @@
} while (err<0 && errno == EINTR);
if (err == 0) {
- mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
+ mHwc.mEventHandler.onVSyncReceived(&mHwc, 0, next_vsync);
}
return true;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index bca25ac..a94bc1e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -62,8 +62,10 @@
public:
class EventHandler {
friend class HWComposer;
- virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
+ virtual void onVSyncReceived(
+ HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
virtual void onHotplugReceived(int disp, bool connected) = 0;
+ virtual void onInvalidateReceived(HWComposer* composer) = 0;
protected:
virtual ~EventHandler() {}
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 30bce55..cbc209d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -579,7 +579,7 @@
// the lock because on creation, it will call back into SurfaceFlinger to
// initialize the primary display.
LOG_ALWAYS_FATAL_IF(mEnterVrMode, "Starting in vr mode is not currently supported.");
- mRealHwc = new HWComposer(this, false);
+ mRealHwc = new HWComposer(false);
mHwc = mRealHwc;
mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
@@ -1102,7 +1102,14 @@
}
}
-void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
+void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type,
+ nsecs_t timestamp) {
+ Mutex::Autolock lock(mStateLock);
+ // Ignore any vsyncs from the non-active hardware composer.
+ if (composer != mHwc) {
+ return;
+ }
+
bool needsHwVsync = false;
{ // Scope for the lock
@@ -1163,6 +1170,20 @@
}
}
+void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) {
+ Mutex::Autolock lock(mStateLock);
+ if (composer == mHwc) {
+ repaintEverything();
+ } else {
+ // This isn't from our current hardware composer. If it's a callback
+ // from the real composer, forward the refresh request to vr
+ // flinger. Otherwise ignore it.
+ if (!composer->isUsingVrComposer()) {
+ mVrFlinger->OnHardwareComposerRefresh();
+ }
+ }
+}
+
void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
ATRACE_CALL();
getHwComposer().setVsyncEnabled(disp,
@@ -1209,7 +1230,7 @@
}
if (!mVrHwc) {
- mVrHwc = new HWComposer(this, true);
+ mVrHwc = new HWComposer(true);
ALOGV("Vr HWC created");
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6dfdf08..02e4a0c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -247,8 +247,9 @@
/* ------------------------------------------------------------------------
* HWComposer::EventHandler interface
*/
- virtual void onVSyncReceived(int type, nsecs_t timestamp);
+ virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp);
virtual void onHotplugReceived(int disp, bool connected);
+ virtual void onInvalidateReceived(HWComposer* composer);
/* ------------------------------------------------------------------------
* Message handling
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 7e6eb03..40a27e8 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1018,7 +1018,8 @@
}
}
-void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+void SurfaceFlinger::onVSyncReceived(HWComposer* /*composer*/, int type,
+ nsecs_t timestamp) {
bool needsHwVsync = false;
{ // Scope for the lock
@@ -1058,6 +1059,10 @@
}
}
+void SurfaceFlinger::onInvalidateReceived(HWComposer* /*composer*/) {
+ repaintEverything();
+}
+
void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
ATRACE_CALL();
getHwComposer().eventControl(disp, event, enabled);
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 32f777d..a23056c 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -739,8 +739,10 @@
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) {