Merge "MediaCas: add plugin APIs"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e33f099..349bbed 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1336,22 +1336,14 @@
return std::string(hash_buffer);
}
-static void SendShellBroadcast(const std::string& action, const std::vector<std::string>& args) {
- std::vector<std::string> am = {
- "/system/bin/cmd", "activity", "broadcast", "--user", "0", "-a", action};
+static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
+ // clang-format off
+ std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
+ "--receiver-foreground", "--receiver-include-background", "-a", action};
+ // clang-format on
am.insert(am.end(), args.begin(), args.end());
- // TODO: explicity setting Shell's component to allow broadcast to launch it.
- // That might break other components that are listening to the bugreport notifications
- // (com.android.internal.intent.action.BUGREPORT_STARTED and
- // com.android.internal.intent.action.BUGREPORT_STOPED), but
- // those should be just handled by Shell anyways.
- // A more generic alternative would be passing the -f 0x01000000 flag (or whatever
- // value is defined by FLAG_RECEIVER_INCLUDE_BACKGROUND), but that would reset the
- // --receiver-foreground option
- am.push_back("com.android.shell");
-
RunCommand("", am,
CommandOptions::WithTimeout(20)
.Log("Sending broadcast: '%s'\n")
@@ -1594,14 +1586,14 @@
// clang-format off
std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
+ "--receiver-permission", "android.permission.DUMP",
"--es", "android.intent.extra.NAME", ds.name_,
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
"--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
};
// clang-format on
- SendShellBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
+ SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
}
if (use_control_socket) {
dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
@@ -1809,7 +1801,7 @@
// clang-format off
std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
+ "--receiver-permission", "android.permission.DUMP",
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
"--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
@@ -1826,10 +1818,10 @@
am_args.push_back("--es");
am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
am_args.push_back(SHA256_file_hash(ds.path_));
- SendShellBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
- am_args);
+ SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
+ am_args);
} else {
- SendShellBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
+ SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
}
} else {
MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index d1bdded..6caf149 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -16,8 +16,9 @@
#include "CacheItem.h"
-#include <stdint.h>
#include <inttypes.h>
+#include <stdint.h>
+#include <sys/xattr.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
@@ -29,12 +30,23 @@
namespace android {
namespace installd {
-CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
+CacheItem::CacheItem(FTSENT* p) {
level = p->fts_level;
directory = S_ISDIR(p->fts_statp->st_mode);
size = p->fts_statp->st_blocks * 512;
modified = p->fts_statp->st_mtime;
- mName = p->fts_path;
+
+ mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
+ if (mParent) {
+ atomic = mParent->atomic;
+ tombstone = mParent->tombstone;
+ mName = p->fts_name;
+ mName.insert(0, "/");
+ } else {
+ atomic = false;
+ tombstone = false;
+ mName = p->fts_path;
+ }
}
CacheItem::~CacheItem() {
@@ -46,7 +58,7 @@
std::string CacheItem::buildPath() {
std::string res = mName;
- std::shared_ptr<CacheItem> parent = mParent;
+ CacheItem* parent = mParent;
while (parent) {
res.insert(0, parent->mName);
parent = parent->mParent;
@@ -57,13 +69,47 @@
int CacheItem::purge() {
auto path = buildPath();
if (directory) {
- return delete_dir_contents_and_dir(path, true);
- } else {
- int res = unlink(path.c_str());
- if (res != 0) {
- PLOG(WARNING) << "Failed to unlink " << path;
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(WARNING) << "Failed to fts_open " << path;
+ return -1;
}
- return res;
+ while ((p = fts_read(fts)) != nullptr) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (p->fts_level == 0) {
+ p->fts_number = tombstone;
+ } else {
+ p->fts_number = p->fts_parent->fts_number
+ | (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
+ }
+ break;
+ case FTS_F:
+ if (p->fts_parent->fts_number) {
+ truncate(p->fts_path, 0);
+ } else {
+ unlink(p->fts_path);
+ }
+ break;
+ case FTS_DEFAULT:
+ case FTS_SL:
+ case FTS_SLNONE:
+ unlink(p->fts_path);
+ break;
+ case FTS_DP:
+ rmdir(p->fts_path);
+ break;
+ }
+ }
+ return 0;
+ } else {
+ if (tombstone) {
+ return truncate(path.c_str(), 0);
+ } else {
+ return unlink(path.c_str());
+ }
}
}
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
index bec8bc8..afbb15d 100644
--- a/cmds/installd/CacheItem.h
+++ b/cmds/installd/CacheItem.h
@@ -36,7 +36,7 @@
*/
class CacheItem {
public:
- CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
+ CacheItem(FTSENT* p);
~CacheItem();
std::string toString();
@@ -46,11 +46,13 @@
short level;
bool directory;
+ bool atomic;
+ bool tombstone;
int64_t size;
time_t modified;
private:
- std::shared_ptr<CacheItem> mParent;
+ CacheItem* mParent;
std::string mName;
DISALLOW_COPY_AND_ASSIGN(CacheItem);
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index 23c4330..9377836 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -20,6 +20,7 @@
#include <fts.h>
#include <sys/quota.h>
+#include <sys/xattr.h>
#include <utils/Trace.h>
#include <android-base/logging.h>
@@ -86,30 +87,59 @@
PLOG(WARNING) << "Failed to fts_open " << path;
return;
}
- // TODO: add support for "user.atomic" and "user.tombstone" xattrs
- while ((p = fts_read(fts)) != NULL) {
+ while ((p = fts_read(fts)) != nullptr) {
+ if (p->fts_level == 0) continue;
+
+ // Create tracking nodes for everything we encounter
switch (p->fts_info) {
case FTS_D:
- // Track the newest mtime of anything inside so we consider
- // deleting the directory last
- p->fts_number = p->fts_statp->st_mtime;
- break;
- case FTS_DP:
- p->fts_statp->st_mtime = p->fts_number;
-
- // Ignore the actual top-level cache directories
- if (p->fts_level == 0) break;
case FTS_DEFAULT:
case FTS_F:
case FTS_SL:
- case FTS_SLNONE:
- // TODO: optimize path memory footprint
- items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
+ case FTS_SLNONE: {
+ auto item = std::shared_ptr<CacheItem>(new CacheItem(p));
+ p->fts_pointer = static_cast<void*>(item.get());
+ items.push_back(item);
+ }
+ }
- // Track the newest modified item under this tree
- p->fts_parent->fts_number =
- std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
- break;
+ switch (p->fts_info) {
+ case FTS_D: {
+ auto item = static_cast<CacheItem*>(p->fts_pointer);
+ item->atomic |= (getxattr(p->fts_path, kXattrCacheAtomic, nullptr, 0) >= 0);
+ item->tombstone |= (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
+
+ // When atomic, immediately collect all files under tree
+ if (item->atomic) {
+ while ((p = fts_read(fts)) != nullptr) {
+ if (p->fts_info == FTS_DP && p->fts_level == item->level) break;
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ item->size += p->fts_statp->st_blocks * 512;
+ item->modified = std::max(item->modified, p->fts_statp->st_mtime);
+ }
+ }
+ }
+ }
+ }
+
+ // Bubble up modified time to parent
+ switch (p->fts_info) {
+ case FTS_DP:
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE: {
+ auto item = static_cast<CacheItem*>(p->fts_pointer);
+ auto parent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
+ if (parent) {
+ parent->modified = std::max(parent->modified, item->modified);
+ }
+ }
}
}
fts_close(fts);
@@ -137,7 +167,7 @@
}
return left->directory;
};
- std::sort(items.begin(), items.end(), cmp);
+ std::stable_sort(items.begin(), items.end(), cmp);
ATRACE_END();
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 535d060..a84b051 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -86,7 +86,8 @@
static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
static constexpr int FLAG_USE_QUOTA = 1 << 12;
static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
+static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
namespace {
@@ -833,6 +834,14 @@
ATRACE_BEGIN("bounce");
std::shared_ptr<CacheTracker> active;
while (active || !queue.empty()) {
+ // Only look at apps under quota when explicitly requested
+ if (active && (active->getCacheRatio() < 10000)
+ && !(flags & FLAG_FREE_CACHE_V2_DEFY_QUOTA)) {
+ LOG(DEBUG) << "Active ratio " << active->getCacheRatio()
+ << " isn't over quota, and defy not requested";
+ break;
+ }
+
// Find the best tracker to work with; this might involve swapping
// if the active tracker is no longer the most over quota
bool nextBetter = active && !queue.empty()
@@ -2014,5 +2023,11 @@
return mQuotaDevices[path];
}
+binder::Status InstalldNativeService::isQuotaSupported(
+ const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
+ *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+ return ok();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index b3dbaf4..feb2219 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -111,6 +111,8 @@
const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
binder::Status invalidateMounts();
+ binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
+ bool* _aidl_return);
private:
std::recursive_mutex mLock;
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index b45df87..4195a01 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -77,4 +77,5 @@
int storage_flag);
void invalidateMounts();
+ boolean isQuotaSupported(@nullable @utf8InCpp String uuid);
}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index a32df22..b5b080d 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -14,3 +14,22 @@
"libdiskusage",
],
}
+
+cc_test {
+ name: "installd_cache_test",
+ clang: true,
+ srcs: ["installd_cache_test.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "liblogwrap",
+ "libselinux",
+ "libutils",
+ ],
+ static_libs: [
+ "libinstalld",
+ "libdiskusage",
+ ],
+}
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
new file mode 100644
index 0000000..50a47d2
--- /dev/null
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2017 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 <stdlib.h>
+#include <string.h>
+#include <sys/statvfs.h>
+#include <sys/xattr.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+constexpr const char* kTestUuid = "TEST";
+
+constexpr int64_t kKbInBytes = 1024;
+constexpr int64_t kMbInBytes = 1024 * kKbInBytes;
+constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
+constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
+
+static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
+static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+
+int get_property(const char *key, char *value, const char *default_value) {
+ return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+ const char *oat_dir ATTRIBUTE_UNUSED,
+ const char *apk_path ATTRIBUTE_UNUSED,
+ const char *instruction_set ATTRIBUTE_UNUSED) {
+ return false;
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+ const char *apk_path ATTRIBUTE_UNUSED,
+ const char *instruction_set ATTRIBUTE_UNUSED) {
+ return false;
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+ const char *src ATTRIBUTE_UNUSED,
+ const char *instruction_set ATTRIBUTE_UNUSED) {
+ return false;
+}
+
+static void mkdir(const char* path) {
+ const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+ ::mkdir(fullPath, 0755);
+}
+
+static void touch(const char* path, int len, int time) {
+ const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+ int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
+ ::fallocate(fd, 0, 0, len);
+ ::close(fd);
+ struct utimbuf times;
+ times.actime = times.modtime = std::time(0) + time;
+ ::utime(fullPath, ×);
+}
+
+static int exists(const char* path) {
+ const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+ return ::access(fullPath, F_OK);
+}
+
+static int64_t size(const char* path) {
+ const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+ struct stat buf;
+ if (!stat(fullPath, &buf)) {
+ return buf.st_size;
+ } else {
+ return -1;
+ }
+}
+
+static int64_t free() {
+ struct statvfs buf;
+ if (!statvfs("/data/local/tmp", &buf)) {
+ return buf.f_bavail * buf.f_bsize;
+ } else {
+ return -1;
+ }
+}
+
+static void setxattr(const char* path, const char* key) {
+ const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+ ::setxattr(fullPath, key, "", 0, 0);
+}
+
+class CacheTest : public testing::Test {
+protected:
+ InstalldNativeService* service;
+ std::unique_ptr<std::string> testUuid;
+
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+
+ service = new InstalldNativeService();
+ testUuid = std::make_unique<std::string>();
+ *testUuid = std::string(kTestUuid);
+ system("mkdir -p /data/local/tmp/user/0");
+ }
+
+ virtual void TearDown() {
+ delete service;
+ system("rm -rf /data/local/tmp/user");
+ }
+};
+
+TEST_F(CacheTest, FreeCache_All) {
+ mkdir("com.example");
+ touch("com.example/normal", 1 * kMbInBytes, 60);
+ mkdir("com.example/cache");
+ mkdir("com.example/cache/foo");
+ touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
+ touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
+
+ EXPECT_EQ(0, exists("com.example/normal"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+ service->freeCache(testUuid, kTbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(0, exists("com.example/normal"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
+}
+
+TEST_F(CacheTest, FreeCache_Age) {
+ mkdir("com.example");
+ mkdir("com.example/cache");
+ mkdir("com.example/cache/foo");
+ touch("com.example/cache/foo/one", kMbInBytes, 60);
+ touch("com.example/cache/foo/two", kMbInBytes, 120);
+
+ service->freeCache(testUuid, free() + kKbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+ service->freeCache(testUuid, free() + kKbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
+}
+
+TEST_F(CacheTest, FreeCache_Tombstone) {
+ mkdir("com.example");
+ mkdir("com.example/cache");
+ mkdir("com.example/cache/foo");
+ touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
+ touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
+ mkdir("com.example/cache/bar");
+ touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
+ touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
+
+ setxattr("com.example/cache/bar", "user.cache_tombstone");
+
+ EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
+ EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
+ EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
+ EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
+ EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
+ EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
+
+ service->freeCache(testUuid, kTbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
+ EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
+ EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
+ EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
+ EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
+}
+
+TEST_F(CacheTest, FreeCache_Atomic) {
+ mkdir("com.example");
+ mkdir("com.example/cache");
+ mkdir("com.example/cache/foo");
+ touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
+ touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
+
+ setxattr("com.example/cache/foo", "user.cache_atomic");
+
+ service->freeCache(testUuid, free() + kKbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
+ EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
+}
+
+TEST_F(CacheTest, FreeCache_AtomicTombstone) {
+ LOG(INFO) << "FreeCache_AtomicTombstone";
+
+ mkdir("com.example");
+ mkdir("com.example/cache");
+
+ // this dir must look really old for some reason?
+ mkdir("com.example/cache/atomic");
+ touch("com.example/cache/atomic/file1", kMbInBytes, 120);
+ touch("com.example/cache/atomic/file2", kMbInBytes, 120);
+ mkdir("com.example/cache/atomic/dir");
+ touch("com.example/cache/atomic/dir/file1", kMbInBytes, 120);
+ touch("com.example/cache/atomic/dir/file2", kMbInBytes, 120);
+ mkdir("com.example/cache/atomic/tomb");
+ touch("com.example/cache/atomic/tomb/file1", kMbInBytes, 120);
+ touch("com.example/cache/atomic/tomb/file2", kMbInBytes, 120);
+ mkdir("com.example/cache/atomic/tomb/dir");
+ touch("com.example/cache/atomic/tomb/dir/file1", kMbInBytes, 120);
+ touch("com.example/cache/atomic/tomb/dir/file2", kMbInBytes, 120);
+
+ mkdir("com.example/cache/tomb");
+ touch("com.example/cache/tomb/file1", kMbInBytes, 240);
+ touch("com.example/cache/tomb/file2", kMbInBytes, 240);
+ mkdir("com.example/cache/tomb/dir");
+ touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
+ touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
+ mkdir("com.example/cache/tomb/atomic");
+ touch("com.example/cache/tomb/atomic/file1", kMbInBytes, 60);
+ touch("com.example/cache/tomb/atomic/file2", kMbInBytes, 60);
+ mkdir("com.example/cache/tomb/atomic/dir");
+ touch("com.example/cache/tomb/atomic/dir/file1", kMbInBytes, 60);
+ touch("com.example/cache/tomb/atomic/dir/file2", kMbInBytes, 60);
+
+ setxattr("com.example/cache/atomic", "user.cache_atomic");
+ setxattr("com.example/cache/atomic/tomb", "user.cache_tombstone");
+ setxattr("com.example/cache/tomb", "user.cache_tombstone");
+ setxattr("com.example/cache/tomb/atomic", "user.cache_atomic");
+
+ service->freeCache(testUuid, free() + kKbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file2"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file2"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file2"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file2"));
+
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+
+ service->freeCache(testUuid, free() + kKbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
+ EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
+ EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
+ EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
+ EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+
+ service->freeCache(testUuid, kTbInBytes,
+ FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+ EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
+ EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
+ EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
+ EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
+ EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+
+ EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
+ EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 947cc0d..4b68574 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -29,6 +29,7 @@
#define TEST_DATA_DIR "/data/"
#define TEST_APP_DIR "/data/app/"
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
+#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
#define TEST_ASEC_DIR "/mnt/asec/"
#define TEST_EXPAND_DIR "/mnt/expand/"
@@ -57,6 +58,9 @@
android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
+ android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
+ android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
+
android_data_dir.path = (char*) TEST_DATA_DIR;
android_data_dir.len = strlen(TEST_DATA_DIR);
@@ -85,19 +89,19 @@
// Bad prefixes directories
const char *badprefix1 = "/etc/passwd";
EXPECT_EQ(-1, validate_apk_path(badprefix1))
- << badprefix1 << " should be allowed as a valid path";
+ << badprefix1 << " should not be allowed as a valid path";
const char *badprefix2 = "../.." TEST_APP_DIR "../../../blah";
EXPECT_EQ(-1, validate_apk_path(badprefix2))
- << badprefix2 << " should be allowed as a valid path";
+ << badprefix2 << " should not be allowed as a valid path";
const char *badprefix3 = "init.rc";
EXPECT_EQ(-1, validate_apk_path(badprefix3))
- << badprefix3 << " should be allowed as a valid path";
+ << badprefix3 << " should not be allowed as a valid path";
const char *badprefix4 = "/init.rc";
EXPECT_EQ(-1, validate_apk_path(badprefix4))
- << badprefix4 << " should be allowed as a valid path";
+ << badprefix4 << " should not be allowed as a valid path";
}
TEST_F(UtilsTest, IsValidApkPath_Internal) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 37215ea..6d50f55 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -33,6 +33,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
+#include <cutils/properties.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
@@ -155,6 +156,9 @@
std::string create_data_path(const char* volume_uuid) {
if (volume_uuid == nullptr) {
return "/data";
+ } else if (!strcmp(volume_uuid, "TEST")) {
+ CHECK(property_get_bool("ro.debuggable", false));
+ return "/data/local/tmp";
} else {
CHECK(is_valid_filename(volume_uuid));
return StringPrintf("/mnt/expand/%s", volume_uuid);
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5226d1c..aa83dc2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -66,6 +66,8 @@
constexpr const char* kXattrInodeCache = "user.inode_cache";
constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
+constexpr const char* kXattrCacheAtomic = "user.cache_atomic";
+constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index ce058c8..6fd9b21 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -469,9 +469,17 @@
return status;
}
+void signalHandler(int sig) {
+ if (sig == SIGINT) {
+ int retVal;
+ pthread_exit(&retVal);
+ }
+}
+
} // namespace lshal
} // namespace android
int main(int argc, char **argv) {
+ signal(SIGINT, ::android::lshal::signalHandler);
return ::android::lshal::Lshal{}.main(argc, argv);
}
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index bf883c0..ca477bf 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -29,7 +29,8 @@
class BackgroundTaskState {
public:
- BackgroundTaskState(){}
+ BackgroundTaskState(std::function<void(void)> &&func)
+ : mFunc(std::forward<decltype(func)>(func)) {}
void notify() {
std::unique_lock<std::mutex> lock(mMutex);
mFinished = true;
@@ -42,22 +43,37 @@
mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
return mFinished;
}
+ void operator()() {
+ mFunc();
+ }
private:
std::mutex mMutex;
std::condition_variable mCondVar;
bool mFinished = false;
+ std::function<void(void)> mFunc;
};
+void *callAndNotify(void *data) {
+ BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
+ state();
+ state.notify();
+ return NULL;
+}
+
template<class R, class P>
-bool timeout(std::chrono::duration<R, P> delay, const std::function<void(void)> &func) {
+bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
auto now = std::chrono::system_clock::now();
- BackgroundTaskState state{};
- std::thread t([&state, &func] {
- func();
- state.notify();
- });
- t.detach();
+ BackgroundTaskState state{std::forward<decltype(func)>(func)};
+ pthread_t thread;
+ if (pthread_create(&thread, NULL, callAndNotify, &state)) {
+ std::cerr << "FATAL: could not create background thread." << std::endl;
+ return false;
+ }
bool success = state.wait(now + delay);
+ if (!success) {
+ pthread_kill(thread, SIGINT);
+ }
+ pthread_join(thread, NULL);
return success;
}
@@ -69,7 +85,7 @@
auto boundFunc = std::bind(std::forward<Function>(func),
interfaceObject.get(), std::forward<Args>(args)...);
bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
- ret = boundFunc();
+ ret = std::move(boundFunc());
});
if (!success) {
return Status::fromStatusT(TIMED_OUT);
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 3ea453f..bb0ca32 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -14,90 +14,90 @@
# Project related configuration options
#---------------------------------------------------------------------------
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
# http://www.gnu.org/software/libiconv for the list of possible encodings.
DOXYFILE_ENCODING = UTF-8
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
PROJECT_NAME = "NDK API"
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER =
+PROJECT_NUMBER =
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = ""
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
PROJECT_LOGO = logo.png
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY =
+OUTPUT_DIRECTORY =
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
CREATE_SUBDIRS = NO
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the"
ABBREVIATE_BRIEF = "The $name class" \
@@ -112,256 +112,256 @@
an \
the
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
# description.
ALWAYS_DETAILED_SEC = NO
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip. Note that you specify absolute paths here, but also
-# relative paths, which will be relative from the directory where doxygen is
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
# started.
-STRIP_FROM_PATH =
+STRIP_FROM_PATH =
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
-STRIP_FROM_INC_PATH =
+STRIP_FROM_INC_PATH =
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
# doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.)
JAVADOC_AUTOBRIEF = NO
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.)
QT_AUTOBRIEF = NO
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
MULTILINE_CPP_IS_BRIEF = NO
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
# re-implements.
INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
# be part of the file/class/namespace that contains it.
SEPARATE_MEMBER_PAGES = NO
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 4
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
# You can put \n's in the value part of an alias to insert newlines.
-ALIASES =
+ALIASES =
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding
-# "class=itcl::class" will allow you to use the command class in the
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
# itcl::class meaning.
-TCL_SUBST =
+TCL_SUBST =
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = YES
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc.
OPTIMIZE_OUTPUT_JAVA = NO
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
# Fortran.
OPTIMIZE_FOR_FORTRAN = NO
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
# VHDL.
OPTIMIZE_OUTPUT_VHDL = NO
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension,
-# and language is one of the parsers supported by doxygen: IDL, Java,
-# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
-# C++. For instance to make doxygen treat .inc files as Fortran files (default
-# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
-# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
# files are not read by doxygen.
-EXTENSION_MAPPING =
+EXTENSION_MAPPING =
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you
-# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
# Disable only in case of backward compatibilities issues.
MARKDOWN_SUPPORT = YES
-# When enabled doxygen tries to link words that correspond to documented classes,
-# or namespaces to their corresponding documentation. Such a link can be
-# prevented in individual cases by by putting a % sign in front of the word or
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
AUTOLINK_SUPPORT = YES
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
BUILTIN_STL_SUPPORT = NO
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
CPP_CLI_SUPPORT = NO
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
# instead of private inheritance when no explicit protection keyword is present.
SIP_SUPPORT = NO
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES (the
-# default) will make doxygen replace the get and set methods by a property in
-# the documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = YES
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
DISTRIBUTE_GROUP_DOC = NO
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
# the \nosubgrouping command.
SUBGROUPING = YES
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
# section (for LaTeX and RTF).
INLINE_GROUPED_CLASSES = NO
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
# pages) or section (for LaTeX and RTF).
INLINE_SIMPLE_STRUCTS = NO
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
TYPEDEF_HIDES_STRUCT = NO
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols.
SYMBOL_CACHE_SIZE = 0
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
-# their name and scope. Since this can be an expensive process and often the
-# same symbol appear multiple times in the code, doxygen keeps a cache of
-# pre-resolved symbols. If the cache is too small doxygen will become slower.
-# If the cache is too large, memory is wasted. The cache size is given by this
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols.
LOOKUP_CACHE_SIZE = 0
@@ -370,329 +370,329 @@
# Build related configuration options
#---------------------------------------------------------------------------
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = YES
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
EXTRACT_PRIVATE = NO
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
# scope will be included in the documentation.
EXTRACT_PACKAGE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = NO
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
EXTRACT_LOCAL_CLASSES = YES
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included.
EXTRACT_LOCAL_METHODS = NO
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
# anonymous namespaces are hidden.
EXTRACT_ANON_NSPACES = NO
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
# documentation.
HIDE_FRIEND_COMPOUNDS = NO
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
# function's detailed documentation block.
HIDE_IN_BODY_DOCS = NO
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
CASE_SENSE_NAMES = NO
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = YES
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = YES
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
# rather than with sharp brackets.
FORCE_LOCAL_INCLUDES = NO
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = YES
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = NO
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = NO
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order.
SORT_GROUP_NAMES = NO
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
# alphabetical list.
SORT_BY_SCOPE_NAME = NO
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
# will still accept a match between prototype and implementation in such cases.
STRICT_PROTO_MATCHING = NO
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
# commands in the documentation.
GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
# \deprecated commands in the documentation.
GENERATE_DEPRECATEDLIST= YES
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if section-label ... \endif
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
# and \cond section-label ... \endcond blocks.
-ENABLED_SECTIONS =
+ENABLED_SECTIONS =
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 26
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
SHOW_USED_FILES = YES
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
SHOW_FILES = YES
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
# is used as the file version. See the manual for examples.
-FILE_VERSION_FILTER =
+FILE_VERSION_FILTER =
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
# DoxygenLayout.xml will be used as the name of the layout file.
-LAYOUT_FILE =
+LAYOUT_FILE =
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path. Do not use
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
# file names with spaces, bibtex cannot handle them.
-CITE_BIB_FILES =
+CITE_BIB_FILES =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
-# The QUIET tag can be used to turn on/off the messages that are generated
+# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
WARNINGS = YES
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
# don't exist or using markup commands wrongly.
WARN_IF_DOC_ERROR = YES
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
# documentation.
WARN_NO_PARAMDOC = NO
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
# be obtained via FILE_VERSION_FILTER)
WARN_FORMAT = "$file:$line: $text"
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
# to stderr.
-WARN_LOGFILE =
+WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../include/android ../../av/include/ndk ../../av/include/camera/ndk
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
# the list of possible encodings.
INPUT_ENCODING = UTF-8
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
FILE_PATTERNS = *.c \
@@ -730,159 +730,159 @@
*.vhd \
*.vhdl
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = YES
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-# Note that relative paths are relative to the directory from which doxygen is
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE =
+EXCLUDE =
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
EXCLUDE_SYMLINKS = NO
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
-EXCLUDE_PATTERNS =
+EXCLUDE_PATTERNS =
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
-EXCLUDE_SYMBOLS =
+EXCLUDE_SYMBOLS =
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH =
+EXAMPLE_PATH =
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
EXAMPLE_PATTERNS = *
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
# Possible values are YES and NO. If left blank NO is used.
EXAMPLE_RECURSIVE = NO
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH =
+IMAGE_PATH =
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
# ignored.
-INPUT_FILTER =
+INPUT_FILTER =
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
-FILTER_PATTERNS =
+FILTER_PATTERNS =
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
# FILTER_SOURCE_FILES is enabled.
-FILTER_SOURCE_PATTERNS =
+FILTER_SOURCE_PATTERNS =
-# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page (index.html).
-# This can be useful if you have a project on for instance GitHub and want reuse
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page (index.html).
+# This can be useful if you have a project on for instance GitHub and want reuse
# the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE =
+USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
SOURCE_BROWSER = NO
-# Setting the INLINE_SOURCES tag to YES will include the body
+# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C, C++ and Fortran comments will always remain visible.
STRIP_CODE_COMMENTS = NO
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
# functions referencing it will be listed.
REFERENCED_BY_RELATION = NO
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
# called/used by that function will be listed.
REFERENCES_RELATION = NO
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code. Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
# will need version 4.8.6 or higher.
USE_HTAGS = NO
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = NO
@@ -891,170 +891,170 @@
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = NO
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
-IGNORE_PREFIX =
+IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = $(HTML_OUTPUT)
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension.
HTML_FILE_EXTENSION = .html
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
# changing the value of configuration settings such as GENERATE_TREEVIEW!
HTML_HEADER = $(HTML_HEADER)
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER = $(HTML_FOOTER)
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If left blank doxygen will
-# generate a default style sheet. Note that it is recommended to use
-# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
# tag will in the future become obsolete.
-HTML_STYLESHEET =
+HTML_STYLESHEET =
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
-# user-defined cascading style sheet that is included after the standard
-# style sheets created by doxygen. Using this option one can overrule
-# certain style aspects. This is preferred over using HTML_STYLESHEET
-# since it does not replace the standard style sheet and is therefor more
-# robust against future updates. Doxygen will copy the style sheet file to
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
# the output directory.
-HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
# the files will be copied as-is; there are no commands or markers available.
-HTML_EXTRA_FILES =
+HTML_EXTRA_FILES =
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the style sheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The allowed range is 0 to 359.
HTML_COLORSTYLE_HUE = 220
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
# grayscales only. A value of 255 will produce the most vivid colors.
HTML_COLORSTYLE_SAT = 0
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
# and 100 does not change the gamma.
HTML_COLORSTYLE_GAMMA = 80
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
# this to NO can help when comparing the output of multiple runs.
HTML_TIMESTAMP = YES
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
# page has loaded.
HTML_DYNAMIC_SECTIONS = NO
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
-# entries shown in the various tree structured indices initially; the user
-# can expand and collapse entries dynamically later on. Doxygen will expand
-# the tree to such a level that at most the specified number of entries are
-# visible (unless a fully collapsed tree already exceeds this amount).
-# So setting the number of entries 1 will produce a full collapsed tree by
-# default. 0 is a special value representing an infinite number of entries
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
# and will result in a full expanded tree by default.
HTML_INDEX_NUM_ENTRIES = 100
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
GENERATE_DOCSET = NO
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
# can be grouped.
DOCSET_FEEDNAME = "Doxygen generated docs"
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
# will append .docset to the name.
DOCSET_BUNDLE_ID = org.doxygen.Project
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
-# identify the documentation publisher. This should be a reverse domain-name
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
# style string, e.g. com.mycompany.MyDocSet.documentation.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
@@ -1063,361 +1063,361 @@
DOCSET_PUBLISHER_NAME = Publisher
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
# written to the html output directory.
-CHM_FILE =
+CHM_FILE =
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
# the HTML help compiler on the generated index.hhp.
-HHC_LOCATION =
+HHC_LOCATION =
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
# it should be included in the master .chm file (NO).
GENERATE_CHI = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
# content.
-CHM_INDEX_ENCODING =
+CHM_INDEX_ENCODING =
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
# normal table of contents (NO) in the .chm file.
BINARY_TOC = NO
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
# to the contents of the HTML help documentation and to the tree view.
TOC_EXPAND = NO
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
# Qt Compressed Help (.qch) of the generated HTML documentation.
GENERATE_QHP = NO
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
# The path specified is relative to the HTML output folder.
-QCH_FILE =
+QCH_FILE =
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE = org.doxygen.Project
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
QHP_VIRTUAL_FOLDER = doc
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
-QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_NAME =
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
# Qt Help Project / Custom Filters</a>.
-QHP_CUST_FILTER_ATTRS =
+QHP_CUST_FILTER_ATTRS =
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
# Qt Help Project / Filter Attributes</a>.
-QHP_SECT_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
-QHG_LOCATION =
+QHG_LOCATION =
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
# the help appears.
GENERATE_ECLIPSEHELP = NO
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
# this name.
ECLIPSE_DOC_ID = org.doxygen.Project
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
# GENERATE_TREEVIEW to YES.
DISABLE_INDEX = YES
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-# Since the tree basically has the same information as the tab index you
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
# could consider to set DISABLE_INDEX to NO when enabling this option.
GENERATE_TREEVIEW = NO
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
# values from appearing in the overview section.
ENUM_VALUES_PER_LINE = 4
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
TREEVIEW_WIDTH = 250
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
# links to external symbols imported via tag files in a separate window.
EXT_LINKS_IN_WINDOW = NO
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
# to force them to be regenerated.
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
# in the HTML output before the changes have effect.
FORMULA_TRANSPARENT = YES
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you may also need to install MathJax separately and
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
# configure the path to it using the MATHJAX_RELPATH option.
USE_MATHJAX = NO
-# When MathJax is enabled you can set the default output format to be used for
-# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
-# SVG. The default value is HTML-CSS, which is slower, but has the best
+# When MathJax is enabled you can set the default output format to be used for
+# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
# compatibility.
MATHJAX_FORMAT = HTML-CSS
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to
-# the MathJax Content Delivery Network so you can quickly see the result without
-# installing MathJax. However, it is strongly recommended to install a local
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax. However, it is strongly recommended to install a local
# copy of MathJax from http://www.mathjax.org before deployment.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
# names that should be enabled during MathJax rendering.
-MATHJAX_EXTENSIONS =
+MATHJAX_EXTENSIONS =
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = NO
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript.
-# There are two flavours of web server based search depending on the
-# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
-# searching and an index file used by the script. When EXTERNAL_SEARCH is
-# enabled the indexing and searching needs to be provided by external tools.
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
# See the manual for details.
SERVER_BASED_SEARCH = NO
-# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain
-# the search results. Doxygen ships with an example indexer (doxyindexer) and
-# search engine (doxysearch.cgi) which are based on the open source search engine
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search engine
# library Xapian. See the manual for configuration details.
EXTERNAL_SEARCH = NO
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will returned the search results when EXTERNAL_SEARCH is enabled.
-# Doxygen ships with an example search engine (doxysearch) which is based on
-# the open source search engine library Xapian. See the manual for configuration
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
# details.
-SEARCHENGINE_URL =
+SEARCHENGINE_URL =
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
# SEARCHDATA_FILE tag the name of this file can be specified.
SEARCHDATA_FILE = searchdata.xml
-# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
# projects and redirect the results back to the right project.
-EXTERNAL_SEARCH_ID =
+EXTERNAL_SEARCH_ID =
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
-# of to a relative location where the documentation can be found.
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
-EXTRA_SEARCH_MAPPINGS =
+EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = NO
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
# Makefile that is written to the output directory.
LATEX_CMD_NAME = latex
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
-EXTRA_PACKAGES =
+EXTRA_PACKAGES =
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
-LATEX_HEADER =
+LATEX_HEADER =
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
# standard footer. Notice: only use this tag if you know what you are doing!
-LATEX_FOOTER =
+LATEX_FOOTER =
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = YES
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = YES
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
LATEX_HIDE_INDICES = NO
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
# such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
# http://en.wikipedia.org/wiki/BibTeX for more info.
LATEX_BIB_STYLE = plain
@@ -1426,68 +1426,68 @@
# configuration options related to the RTF output
#---------------------------------------------------------------------------
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = NO
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
-# Load style sheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
-RTF_STYLESHEET_FILE =
+RTF_STYLESHEET_FILE =
-# Set optional variables used in the generation of an rtf document.
+# Set optional variables used in the generation of an rtf document.
# Syntax is similar to doxygen's config file.
-RTF_EXTENSIONS_FILE =
+RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = NO
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
-# The MAN_EXTENSION tag determines the extension that is added to
+# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
MAN_LINKS = NO
@@ -1496,33 +1496,33 @@
# configuration options related to the XML output
#---------------------------------------------------------------------------
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `xml' will be used as the default path.
XML_OUTPUT = xml
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
# syntax of the XML files.
-XML_SCHEMA =
+XML_SCHEMA =
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
# syntax of the XML files.
-XML_DTD =
+XML_DTD =
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
@@ -1531,10 +1531,10 @@
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
# and incomplete at the moment.
GENERATE_AUTOGEN_DEF = NO
@@ -1543,97 +1543,97 @@
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
# moment.
GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
# to generate PDF and DVI output from the Perl module output.
PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
PERLMOD_PRETTY = YES
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
# Makefile don't overwrite each other's variables.
-PERLMOD_MAKEVAR_PREFIX =
+PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
# files.
-ENABLE_PREPROCESSING = YES
+ENABLE_PREPROCESSING = NO
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# pointed to by INCLUDE_PATH will be searched when a #include is found.
SEARCH_INCLUDES = YES
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
# the preprocessor.
-INCLUDE_PATH =
+INCLUDE_PATH =
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
-INCLUDE_FILE_PATTERNS =
+INCLUDE_FILE_PATTERNS =
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED =
+PREDEFINED =
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
# overrules the definition found in the source code.
-EXPAND_AS_DEFINED =
+EXPAND_AS_DEFINED =
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
# semicolon, because these will confuse the parser if not removed.
SKIP_FUNCTION_MACROS = YES
@@ -1642,37 +1642,37 @@
# Configuration::additions related to external references
#---------------------------------------------------------------------------
-# The TAGFILES option can be used to specify one or more tagfiles. For each
-# tag file the location of the external documentation should be added. The
-# format of a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths
-# or URLs. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
# doxygen is run, you must also specify the path to the tagfile here.
-TAGFILES =
+TAGFILES =
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
-GENERATE_TAGFILE =
+GENERATE_TAGFILE =
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
# will be listed.
ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
# be listed.
EXTERNAL_GROUPS = YES
-# The PERL_PATH should be the absolute path and name of the perl script
+# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
@@ -1681,222 +1681,222 @@
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
# install and use dot, since it yields more powerful graphs.
CLASS_DIAGRAMS = NO
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
-MSCGEN_PATH =
+MSCGEN_PATH =
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
# or is not a class.
HIDE_UNDOC_RELATIONS = YES
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = NO
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
# between CPU load and processing speed.
DOT_NUM_THREADS = 0
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font.
DOT_FONTNAME = Helvetica
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
DOT_FONTSIZE = 10
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
# set the path where dot can find it.
-DOT_FONTPATH =
+DOT_FONTPATH =
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
# CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies
GROUP_GRAPHS = YES
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
UML_LOOK = NO
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside
-# the class node. If there are many fields or methods and many nodes the
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
-# threshold limits the number of items for each type to make the size more
-# managable. Set this to 0 for no limit. Note that the threshold may be
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
# exceeded by 50% before the limit is enforced.
UML_LIMIT_NUM_FIELDS = 10
-# If set to YES, the inheritance and collaboration graphs will show the
+# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
TEMPLATE_RELATIONS = NO
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
# other documented files.
INCLUDE_GRAPH = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
# indirectly include this file.
INCLUDED_BY_GRAPH = YES
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
CALL_GRAPH = NO
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
CALLER_GRAPH = NO
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will generate a graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
DIRECTORY_GRAPH = YES
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible in IE 9+ (other browsers do not have this requirement).
DOT_IMAGE_FORMAT = png
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible. Older versions of IE do not have SVG support.
INTERACTIVE_SVG = NO
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
-DOT_PATH =
+DOT_PATH =
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
# \dotfile command).
-DOTFILE_DIRS =
+DOTFILE_DIRS =
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
# \mscfile command).
-MSCFILE_DIRS =
+MSCFILE_DIRS =
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
DOT_GRAPH_MAX_NODES = 50
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
MAX_DOT_GRAPH_DEPTH = 0
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
# a graph (i.e. they become hard to read).
DOT_TRANSPARENT = NO
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
# support this, this feature is disabled by default.
DOT_MULTI_TARGETS = NO
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
# arrows in the dot generated graphs.
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
# the various graphs.
DOT_CLEANUP = YES
diff --git a/include/ui/ANativeObjectBase.h b/include/ui/ANativeObjectBase.h
index 76e850f..640e34b 100644
--- a/include/ui/ANativeObjectBase.h
+++ b/include/ui/ANativeObjectBase.h
@@ -18,9 +18,7 @@
#define ANDROID_ANDROID_NATIVES_H
#include <sys/types.h>
-#include <string.h>
-#include <hardware/gralloc.h>
#include <system/window.h>
// ---------------------------------------------------------------------------
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
index e9260b5..8c4acb7 100644
--- a/include/ui/ColorSpace.h
+++ b/include/ui/ColorSpace.h
@@ -23,10 +23,10 @@
#include <memory>
#include <string>
-#include <ui/mat3.h>
-#include <ui/scalar.h>
-#include <ui/vec2.h>
-#include <ui/vec3.h>
+#include <math/mat3.h>
+#include <math/scalar.h>
+#include <math/vec2.h>
+#include <math/vec3.h>
namespace android {
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
index 842806e..94caf6b 100644
--- a/include/ui/DisplayInfo.h
+++ b/include/ui/DisplayInfo.h
@@ -19,9 +19,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Timers.h>
-#include <ui/PixelFormat.h>
+#include <utils/Timers.h>
namespace android {
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
index 640e29c..90713b3 100644
--- a/include/ui/Gralloc1.h
+++ b/include/ui/Gralloc1.h
@@ -19,10 +19,17 @@
#define GRALLOC1_LOG_TAG "Gralloc1"
-#include <ui/Gralloc1On0Adapter.h>
-
+#include <functional>
+#include <memory>
#include <unordered_set>
+#include <log/log.h>
+
+#include <ui/Fence.h>
+
+#include <hardware/gralloc1.h>
+
+
namespace std {
template <>
struct hash<gralloc1_capability_t> {
@@ -33,10 +40,42 @@
}
namespace android {
-
+class GraphicBuffer;
class Fence;
class GraphicBuffer;
+class Gralloc1On0Adapter;
+} // namespace android
+
+// This is not an "official" capability (i.e., it is not found in gralloc1.h),
+// but we will use it to detect that we are running through the adapter, which
+// is capable of collaborating with GraphicBuffer such that queries on a
+// buffer_handle_t succeed
+static const auto GRALLOC1_CAPABILITY_ON_ADAPTER =
+ static_cast<gralloc1_capability_t>(GRALLOC1_LAST_CAPABILITY + 1);
+
+static const auto GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER =
+ static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 1);
+static const auto GRALLOC1_FUNCTION_ALLOCATE_WITH_ID =
+ static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 2);
+static const auto GRALLOC1_FUNCTION_LOCK_YCBCR =
+ static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 3);
+static const auto GRALLOC1_LAST_ADAPTER_FUNCTION = GRALLOC1_FUNCTION_LOCK_YCBCR;
+
+typedef gralloc1_error_t (*GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER)(
+ gralloc1_device_t* device, const android::GraphicBuffer* buffer);
+typedef gralloc1_error_t (*GRALLOC1_PFN_ALLOCATE_WITH_ID)(
+ gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptor,
+ gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+typedef int32_t /*gralloc1_error_t*/ (*GRALLOC1_PFN_LOCK_YCBCR)(
+ gralloc1_device_t* device, buffer_handle_t buffer,
+ uint64_t /*gralloc1_producer_usage_t*/ producerUsage,
+ uint64_t /*gralloc1_consumer_usage_t*/ consumerUsage,
+ const gralloc1_rect_t* accessRegion, struct android_ycbcr* outYCbCr,
+ int32_t acquireFence);
+
+
+namespace android {
namespace Gralloc1 {
class Device;
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
index b09fdc6..6379a08 100644
--- a/include/ui/Gralloc1On0Adapter.h
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -35,33 +35,6 @@
struct gralloc_module_t;
-// This is not an "official" capability (i.e., it is not found in gralloc1.h),
-// but we will use it to detect that we are running through the adapter, which
-// is capable of collaborating with GraphicBuffer such that queries on a
-// buffer_handle_t succeed
-static const auto GRALLOC1_CAPABILITY_ON_ADAPTER =
- static_cast<gralloc1_capability_t>(GRALLOC1_LAST_CAPABILITY + 1);
-
-static const auto GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER =
- static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 1);
-static const auto GRALLOC1_FUNCTION_ALLOCATE_WITH_ID =
- static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 2);
-static const auto GRALLOC1_FUNCTION_LOCK_YCBCR =
- static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 3);
-static const auto GRALLOC1_LAST_ADAPTER_FUNCTION = GRALLOC1_FUNCTION_LOCK_YCBCR;
-
-typedef gralloc1_error_t (*GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER)(
- gralloc1_device_t* device, const android::GraphicBuffer* buffer);
-typedef gralloc1_error_t (*GRALLOC1_PFN_ALLOCATE_WITH_ID)(
- gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptor,
- gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
-typedef int32_t /*gralloc1_error_t*/ (*GRALLOC1_PFN_LOCK_YCBCR)(
- gralloc1_device_t* device, buffer_handle_t buffer,
- uint64_t /*gralloc1_producer_usage_t*/ producerUsage,
- uint64_t /*gralloc1_consumer_usage_t*/ consumerUsage,
- const gralloc1_rect_t* accessRegion, struct android_ycbcr* outYCbCr,
- int32_t acquireFence);
-
namespace android {
class Gralloc1On0Adapter : public gralloc1_device_t
diff --git a/include/ui/GrallocMapper.h b/include/ui/GrallocMapper.h
index 5a23b68..5a0d64b 100644
--- a/include/ui/GrallocMapper.h
+++ b/include/ui/GrallocMapper.h
@@ -17,8 +17,6 @@
#ifndef ANDROID_UI_GRALLOC_MAPPER_H
#define ANDROID_UI_GRALLOC_MAPPER_H
-#include <memory>
-
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <system/window.h>
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 759c9ec..040d1e7 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -20,13 +20,15 @@
#include <stdint.h>
#include <sys/types.h>
+#include <string>
+
#include <ui/ANativeObjectBase.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <utils/Flattenable.h>
#include <utils/RefBase.h>
-#include <string>
+#include <hardware/gralloc.h>
struct ANativeWindowBuffer;
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 2ccc44b..e97122b 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -20,11 +20,14 @@
#include <stdint.h>
+#include <memory>
+#include <string>
+
#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
#include <utils/Singleton.h>
#include <ui/Gralloc1.h>
@@ -36,7 +39,6 @@
class Allocator;
}
-class Gralloc1Loader;
class GraphicBufferMapper;
class String8;
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index 001769f..b6d4021 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -20,10 +20,18 @@
#include <stdint.h>
#include <sys/types.h>
+#include <memory>
+
#include <ui/Gralloc1.h>
#include <utils/Singleton.h>
+
+// Needed by code that still uses the GRALLOC_USAGE_* constants.
+// when/if we get rid of gralloc, we should provide aliases or fix call sites.
+#include <hardware/gralloc.h>
+
+
namespace android {
// ---------------------------------------------------------------------------
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
new file mode 100644
index 0000000..3ef8b4a
--- /dev/null
+++ b/libs/math/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2017 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.
+
+cc_library_static {
+ name: "libmath",
+ host_supported: true,
+ export_include_dirs: ["include"],
+}
+
+subdirs = ["tests"]
diff --git a/libs/math/MODULE_LICENSE_APACHE2 b/libs/math/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/math/MODULE_LICENSE_APACHE2
diff --git a/libs/math/NOTICE b/libs/math/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/math/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/include/ui/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
similarity index 98%
rename from include/ui/TMatHelpers.h
rename to libs/math/include/math/TMatHelpers.h
index 8edf5f8..478e702 100644
--- a/include/ui/TMatHelpers.h
+++ b/libs/math/include/math/TMatHelpers.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef UI_TMATHELPERS_H_
-#define UI_TMATHELPERS_H_
+#pragma once
#include <math.h>
#include <stdint.h>
@@ -26,8 +25,8 @@
#include <iomanip>
#include <stdexcept>
-#include <ui/quat.h>
-#include <ui/TVecHelpers.h>
+#include <math/quat.h>
+#include <math/TVecHelpers.h>
#include <utils/String8.h>
@@ -636,5 +635,3 @@
#undef UNLIKELY
#undef PURE
#undef CONSTEXPR
-
-#endif // UI_TMATHELPERS_H_
diff --git a/include/ui/TQuatHelpers.h b/libs/math/include/math/TQuatHelpers.h
similarity index 98%
rename from include/ui/TQuatHelpers.h
rename to libs/math/include/math/TQuatHelpers.h
index 2f0f70f..f0a71ae 100644
--- a/include/ui/TQuatHelpers.h
+++ b/libs/math/include/math/TQuatHelpers.h
@@ -15,8 +15,7 @@
*/
-#ifndef UI_TQUATHELPERS_H_
-#define UI_TQUATHELPERS_H_
+#pragma once
#include <math.h>
#include <stdint.h>
@@ -24,7 +23,7 @@
#include <iostream>
-#include <ui/vec3.h>
+#include <math/vec3.h>
#define PURE __attribute__((pure))
@@ -299,6 +298,3 @@
// -------------------------------------------------------------------------------------
} // namespace details
} // namespace android
-
-
-#endif // UI_TQUATHELPERS_H_
diff --git a/include/ui/TVecHelpers.h b/libs/math/include/math/TVecHelpers.h
similarity index 99%
rename from include/ui/TVecHelpers.h
rename to libs/math/include/math/TVecHelpers.h
index 1884608..20f852f 100644
--- a/include/ui/TVecHelpers.h
+++ b/libs/math/include/math/TVecHelpers.h
@@ -15,8 +15,7 @@
*/
-#ifndef UI_TVECHELPERS_H_
-#define UI_TVECHELPERS_H_
+#pragma once
#include <math.h>
#include <stdint.h>
@@ -607,6 +606,3 @@
// -------------------------------------------------------------------------------------
} // namespace details
} // namespace android
-
-
-#endif // UI_TVECHELPERS_H_
diff --git a/include/ui/half.h b/libs/math/include/math/half.h
similarity index 98%
rename from include/ui/half.h
rename to libs/math/include/math/half.h
index 7a271dc..3ca8bd1 100644
--- a/include/ui/half.h
+++ b/libs/math/include/math/half.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef UI_HALF_H
-#define UI_HALF_H
+#pragma once
#include <stdint.h>
#include <iosfwd>
@@ -204,5 +203,3 @@
#undef LIKELY
#undef UNLIKELY
#undef CONSTEXPR
-
-#endif // UI_HALF_H
diff --git a/include/ui/mat2.h b/libs/math/include/math/mat2.h
similarity index 98%
rename from include/ui/mat2.h
rename to libs/math/include/math/mat2.h
index 37c7221..3e6cd4c 100644
--- a/include/ui/mat2.h
+++ b/libs/math/include/math/mat2.h
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#ifndef UI_MAT2_H_
-#define UI_MAT2_H_
+#pragma once
-#include <ui/TMatHelpers.h>
-#include <ui/vec2.h>
+#include <math/TMatHelpers.h>
+#include <math/vec2.h>
#include <stdint.h>
#include <sys/types.h>
@@ -376,5 +375,3 @@
#undef PURE
#undef CONSTEXPR
-
-#endif // UI_MAT2_H_
diff --git a/include/ui/mat3.h b/libs/math/include/math/mat3.h
similarity index 98%
rename from include/ui/mat3.h
rename to libs/math/include/math/mat3.h
index 4f5dba9..5c8a9b2 100644
--- a/include/ui/mat3.h
+++ b/libs/math/include/math/mat3.h
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#ifndef UI_MAT3_H_
-#define UI_MAT3_H_
+#pragma once
-#include <ui/quat.h>
-#include <ui/TMatHelpers.h>
-#include <ui/vec3.h>
+#include <math/quat.h>
+#include <math/TMatHelpers.h>
+#include <math/vec3.h>
#include <stdint.h>
#include <sys/types.h>
@@ -439,5 +438,3 @@
#undef PURE
#undef CONSTEXPR
-
-#endif // UI_MAT3_H_
diff --git a/include/ui/mat4.h b/libs/math/include/math/mat4.h
similarity index 98%
rename from include/ui/mat4.h
rename to libs/math/include/math/mat4.h
index f63d40a..6119ba7 100644
--- a/include/ui/mat4.h
+++ b/libs/math/include/math/mat4.h
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#ifndef UI_MAT4_H_
-#define UI_MAT4_H_
+#pragma once
-#include <ui/mat3.h>
-#include <ui/quat.h>
-#include <ui/TMatHelpers.h>
-#include <ui/vec3.h>
-#include <ui/vec4.h>
+#include <math/mat3.h>
+#include <math/quat.h>
+#include <math/TMatHelpers.h>
+#include <math/vec3.h>
+#include <math/vec4.h>
#include <stdint.h>
#include <sys/types.h>
@@ -585,5 +584,3 @@
#undef PURE
#undef CONSTEXPR
-
-#endif // UI_MAT4_H_
diff --git a/include/ui/quat.h b/libs/math/include/math/quat.h
similarity index 97%
rename from include/ui/quat.h
rename to libs/math/include/math/quat.h
index 5b8cd8b..1936a2b 100644
--- a/include/ui/quat.h
+++ b/libs/math/include/math/quat.h
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-#ifndef UI_QUAT_H_
-#define UI_QUAT_H_
+#pragma once
-#include <ui/half.h>
-#include <ui/TQuatHelpers.h>
-#include <ui/vec3.h>
-#include <ui/vec4.h>
+#include <math/half.h>
+#include <math/TQuatHelpers.h>
+#include <math/vec3.h>
+#include <math/vec4.h>
#include <stdint.h>
#include <sys/types.h>
@@ -191,5 +190,3 @@
#pragma clang diagnostic pop
#undef PURE
-
-#endif // UI_QUAT_H_
diff --git a/include/ui/scalar.h b/libs/math/include/math/scalar.h
similarity index 94%
rename from include/ui/scalar.h
rename to libs/math/include/math/scalar.h
index 5f8329e..2eced92 100644
--- a/include/ui/scalar.h
+++ b/libs/math/include/math/scalar.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef UI_SCALAR_H
-#define UI_SCALAR_H
+#pragma once
#include <algorithm>
#include <cmath>
@@ -43,5 +42,3 @@
}
} // namespace std
-
-#endif // UI_SCALAR_H
diff --git a/include/ui/vec2.h b/libs/math/include/math/vec2.h
similarity index 96%
rename from include/ui/vec2.h
rename to libs/math/include/math/vec2.h
index 308d2b8..a347633 100644
--- a/include/ui/vec2.h
+++ b/libs/math/include/math/vec2.h
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#ifndef UI_VEC2_H_
-#define UI_VEC2_H_
+#pragma once
-#include <ui/TVecHelpers.h>
-#include <ui/half.h>
+#include <math/TVecHelpers.h>
+#include <math/half.h>
#include <assert.h>
#include <stdint.h>
#include <sys/types.h>
@@ -124,5 +123,3 @@
} // namespace android
#pragma clang diagnostic pop
-
-#endif // UI_VEC2_H_
diff --git a/include/ui/vec3.h b/libs/math/include/math/vec3.h
similarity index 97%
rename from include/ui/vec3.h
rename to libs/math/include/math/vec3.h
index e3a6d14..009fd84 100644
--- a/include/ui/vec3.h
+++ b/libs/math/include/math/vec3.h
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#ifndef UI_VEC3_H_
-#define UI_VEC3_H_
+#pragma once
-#include <ui/vec2.h>
-#include <ui/half.h>
+#include <math/vec2.h>
+#include <math/half.h>
#include <stdint.h>
#include <sys/types.h>
@@ -130,5 +129,3 @@
} // namespace android
#pragma clang diagnostic pop
-
-#endif // UI_VEC3_H_
diff --git a/include/ui/vec4.h b/libs/math/include/math/vec4.h
similarity index 96%
rename from include/ui/vec4.h
rename to libs/math/include/math/vec4.h
index 9346fb3..1e279fe 100644
--- a/include/ui/vec4.h
+++ b/libs/math/include/math/vec4.h
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#ifndef UI_VEC4_H_
-#define UI_VEC4_H_
+#pragma once
-#include <ui/vec3.h>
-#include <ui/half.h>
+#include <math/vec3.h>
+#include <math/half.h>
#include <stdint.h>
#include <sys/types.h>
@@ -127,5 +126,3 @@
} // namespace android
#pragma clang diagnostic pop
-
-#endif // UI_VEC4_H_
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
new file mode 100644
index 0000000..0ed24a2
--- /dev/null
+++ b/libs/math/tests/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2014 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.
+//
+
+cc_test {
+ name: "vec_test",
+ srcs: ["vec_test.cpp"],
+ static_libs: ["libmath"],
+}
+
+cc_test {
+ name: "mat_test",
+ srcs: ["mat_test.cpp"],
+ static_libs: ["libmath"],
+}
+
+cc_test {
+ name: "half_test",
+ srcs: ["half_test.cpp"],
+ static_libs: ["libmath"],
+}
+
+cc_test {
+ name: "quat_test",
+ srcs: ["quat_test.cpp"],
+ static_libs: ["libmath"],
+}
diff --git a/libs/ui/tests/half_test.cpp b/libs/math/tests/half_test.cpp
similarity index 98%
rename from libs/ui/tests/half_test.cpp
rename to libs/math/tests/half_test.cpp
index b2a5e5c..496a7ef 100644
--- a/libs/ui/tests/half_test.cpp
+++ b/libs/math/tests/half_test.cpp
@@ -19,8 +19,8 @@
#include <math.h>
#include <stdlib.h>
-#include <ui/half.h>
-#include <ui/vec4.h>
+#include <math/half.h>
+#include <math/vec4.h>
#include <gtest/gtest.h>
diff --git a/libs/ui/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp
similarity index 99%
rename from libs/ui/tests/mat_test.cpp
rename to libs/math/tests/mat_test.cpp
index 0f8e631..c365366 100644
--- a/libs/ui/tests/mat_test.cpp
+++ b/libs/math/tests/mat_test.cpp
@@ -24,8 +24,8 @@
#include <gtest/gtest.h>
-#include <ui/mat2.h>
-#include <ui/mat4.h>
+#include <math/mat2.h>
+#include <math/mat4.h>
namespace android {
diff --git a/libs/ui/tests/quat_test.cpp b/libs/math/tests/quat_test.cpp
similarity index 98%
rename from libs/ui/tests/quat_test.cpp
rename to libs/math/tests/quat_test.cpp
index f5cb659..c20771e 100644
--- a/libs/ui/tests/quat_test.cpp
+++ b/libs/math/tests/quat_test.cpp
@@ -22,10 +22,10 @@
#include <random>
#include <functional>
-#include <ui/quat.h>
-#include <ui/mat4.h>
-#include <ui/vec3.h>
-#include <ui/vec4.h>
+#include <math/quat.h>
+#include <math/mat4.h>
+#include <math/vec3.h>
+#include <math/vec4.h>
#include <gtest/gtest.h>
diff --git a/libs/ui/tests/vec_test.cpp b/libs/math/tests/vec_test.cpp
similarity index 99%
rename from libs/ui/tests/vec_test.cpp
rename to libs/math/tests/vec_test.cpp
index 7c749a7..79ae2e4 100644
--- a/libs/ui/tests/vec_test.cpp
+++ b/libs/math/tests/vec_test.cpp
@@ -19,7 +19,7 @@
#include <math.h>
#include <stdlib.h>
-#include <ui/vec4.h>
+#include <math/vec4.h>
#include <gtest/gtest.h>
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index ea18644..d1bfa18 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -78,9 +78,13 @@
static_libs: [
"libarect",
+ "libmath",
],
- export_static_lib_headers: ["libarect"],
+ export_static_lib_headers: [
+ "libarect",
+ "libmath",
+ ],
}
subdirs = ["tests"]
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
index 7952ed6..64a8b40 100644
--- a/libs/ui/Gralloc1.cpp
+++ b/libs/ui/Gralloc1.cpp
@@ -18,6 +18,7 @@
#include <ui/Gralloc1.h>
#include <ui/GraphicBuffer.h>
+#include <ui/Gralloc1On0Adapter.h>
#include <vector>
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
index 4cc0e4b..b8bc6c4 100644
--- a/libs/ui/Gralloc1On0Adapter.cpp
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -18,10 +18,13 @@
#define LOG_TAG "Gralloc1On0Adapter"
//#define LOG_NDEBUG 0
+#include <ui/Gralloc1On0Adapter.h>
+
+
#include <hardware/gralloc.h>
-#include <ui/Gralloc1On0Adapter.h>
#include <ui/GraphicBuffer.h>
+#include <ui/Gralloc1.h>
#include <utils/Log.h>
diff --git a/libs/ui/GrallocAllocator.cpp b/libs/ui/GrallocAllocator.cpp
index ca67990..5c5d5b3 100644
--- a/libs/ui/GrallocAllocator.cpp
+++ b/libs/ui/GrallocAllocator.cpp
@@ -16,9 +16,10 @@
#define LOG_TAG "GrallocAllocator"
-#include <log/log.h>
#include <ui/GrallocAllocator.h>
+#include <log/log.h>
+
namespace android {
namespace Gralloc2 {
diff --git a/libs/ui/GrallocMapper.cpp b/libs/ui/GrallocMapper.cpp
index b9e9040..6884dcb 100644
--- a/libs/ui/GrallocMapper.cpp
+++ b/libs/ui/GrallocMapper.cpp
@@ -16,11 +16,9 @@
#define LOG_TAG "GrallocMapper"
-#include <array>
-#include <string>
+#include <ui/GrallocMapper.h>
#include <log/log.h>
-#include <ui/GrallocMapper.h>
namespace android {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index b544426..37ebfb3 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -16,18 +16,10 @@
#define LOG_TAG "GraphicBuffer"
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/GrallocMapper.h>
#include <ui/GraphicBuffer.h>
+#include <ui/GrallocMapper.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
-#include <ui/PixelFormat.h>
namespace android {
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index b14110e..3f18bbc 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -18,13 +18,15 @@
#define LOG_TAG "GraphicBufferAllocator"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <ui/GraphicBufferAllocator.h>
+
+#include <stdio.h>
+
#include <log/log.h>
#include <utils/Singleton.h>
#include <utils/String8.h>
#include <utils/Trace.h>
-#include <ui/GraphicBufferAllocator.h>
-#include <ui/Gralloc1On0Adapter.h>
#include <ui/GrallocAllocator.h>
#include <ui/GrallocMapper.h>
#include <ui/GraphicBufferMapper.h>
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index f418f7f..656472f 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -18,8 +18,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
-#include <stdint.h>
-#include <errno.h>
+#include <ui/GraphicBufferMapper.h>
// We would eliminate the non-conforming zero-length array, but we can't since
// this is effectively included from the Linux kernel
@@ -28,13 +27,10 @@
#include <sync/sync.h>
#pragma clang diagnostic pop
-#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Trace.h>
-#include <ui/Gralloc1On0Adapter.h>
#include <ui/GrallocMapper.h>
-#include <ui/GraphicBufferMapper.h>
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index c4f34d5..6733505 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -21,26 +21,6 @@
}
cc_test {
- name: "vec_test",
- srcs: ["vec_test.cpp"],
-}
-
-cc_test {
- name: "mat_test",
- srcs: ["mat_test.cpp"],
-}
-
-cc_test {
- name: "half_test",
- srcs: ["half_test.cpp"],
-}
-
-cc_test {
- name: "quat_test",
- srcs: ["quat_test.cpp"],
-}
-
-cc_test {
name: "colorspace_test",
shared_libs: ["libui"],
srcs: ["colorspace_test.cpp"],
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index f454b08..8fd3627 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -41,6 +41,23 @@
delete client;
}
+int dvrDisplayManagerClientGetEventFd(DvrDisplayManagerClient* client) {
+ return client->client->event_fd();
+}
+
+int dvrDisplayManagerClientTranslateEpollEventMask(
+ DvrDisplayManagerClient* client, int in_events, int* out_events) {
+ auto result = client->client->GetChannel()->GetEventMask(in_events);
+
+ if (!result) {
+ return -EIO;
+ }
+
+ *out_events = result.get();
+
+ return 0;
+}
+
int dvrDisplayManagerClientGetSurfaceList(
DvrDisplayManagerClient* client,
DvrDisplayManagerClientSurfaceList** surface_list) {
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
index f28c1e4..8ba9175 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -19,6 +19,21 @@
void dvrDisplayManagerClientDestroy(DvrDisplayManagerClient* client);
+// Return an event fd for checking if there was an event on the server
+// Note that the only event which will be flagged is POLLIN. You must use
+// dvrDisplayManagerClientTranslateEpollEventMask in order to get the real
+// event flags.
+// @return the fd
+int dvrDisplayManagerClientGetEventFd(DvrDisplayManagerClient* client);
+
+// Once you have received an epoll event, you must translate it to its true
+// flags. This is a workaround for working with UDS.
+// @param in_events pass in the epoll revents that were initially returned
+// @param on success, this value will be overwritten with the true epoll values
+// @return 0 on success, non-zero otherwise
+int dvrDisplayManagerClientTranslateEpollEventMask(
+ DvrDisplayManagerClient* client, int in_events, int* out_events);
+
// If successful, populates |surface_list| with a list of application
// surfaces the display is currently using.
//
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
index 645ccce..4ecd8d4 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
@@ -20,6 +20,9 @@
int GetSurfaceBuffers(
int surface_id, std::vector<std::unique_ptr<BufferConsumer>>* consumers);
+ using Client::event_fd;
+ using Client::GetChannel;
+
private:
friend BASE;
diff --git a/libs/vr/libdvrgraphics/Android.mk b/libs/vr/libdvrgraphics/Android.mk
index b95b18e..b9e601c 100644
--- a/libs/vr/libdvrgraphics/Android.mk
+++ b/libs/vr/libdvrgraphics/Android.mk
@@ -29,6 +29,9 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(includeFiles)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
+# Rather than add this header-file-only library to all users of libdvrgraphics,
+# include it here.
+LOCAL_WHOLE_STATIC_LIBRARIES := libarect
LOCAL_MODULE := libdvrgraphics
include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/vr/libposepredictor/Android.mk b/libs/vr/libposepredictor/Android.mk
old mode 100644
new mode 100755
index 030f79c..2217819
--- a/libs/vr/libposepredictor/Android.mk
+++ b/libs/vr/libposepredictor/Android.mk
@@ -15,15 +15,18 @@
LOCAL_PATH := $(call my-dir)
sourceFiles := \
- linear_pose_predictor.cpp \
+ predictor.cpp \
+ buffered_predictor.cpp \
+ linear_predictor.cpp \
+ polynomial_predictor.cpp \
+ dvr_pose_predictor.cpp \
includeFiles := \
- $(LOCAL_PATH)/include
+ $(LOCAL_PATH)/include \
+ external/eigen \
staticLibraries := \
- libdvrcommon \
libsensor \
- libpdx_default_transport \
sharedLibraries := \
@@ -39,11 +42,12 @@
LOCAL_MODULE := libposepredictor
include $(BUILD_STATIC_LIBRARY)
-
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- linear_pose_predictor_tests.cpp \
+ predictor_tests.cpp \
+ linear_predictor_tests.cpp \
+ polynomial_predictor_tests.cpp \
LOCAL_STATIC_LIBRARIES := libposepredictor $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
diff --git a/libs/vr/libposepredictor/buffered_predictor.cpp b/libs/vr/libposepredictor/buffered_predictor.cpp
new file mode 100644
index 0000000..f3b41dc
--- /dev/null
+++ b/libs/vr/libposepredictor/buffered_predictor.cpp
@@ -0,0 +1,38 @@
+#include <buffered_predictor.h>
+
+namespace posepredictor {
+
+BufferedPredictor::BufferedPredictor(size_t buffer_size) {
+ buffer_.resize(buffer_size);
+}
+
+void BufferedPredictor::BufferSample(const Pose& sample) {
+ const auto& prev_sample = buffer_[current_pose_index_];
+
+ // If we are updating a sample (the same time stamp), do not advance the
+ // counter.
+ if (sample.time_ns != prev_sample.time_ns) {
+ current_pose_index_ = (current_pose_index_ + 1) % buffer_.size();
+ }
+
+ buffer_[current_pose_index_] = sample;
+
+ // Make sure the subsequent orientations are the closest in quaternion space.
+ if (PrevSample(1).orientation.coeffs().dot(sample.orientation.coeffs()) < 0) {
+ // Flip the quaternion to be closest to the previous sample.
+ buffer_[current_pose_index_].orientation =
+ quat(-sample.orientation.w(), -sample.orientation.x(),
+ -sample.orientation.y(), -sample.orientation.z());
+ }
+
+ ++num_poses_added_;
+}
+
+const Pose& BufferedPredictor::PrevSample(size_t index) const {
+ // We must not request a pose too far in the past.
+ assert(index < buffer_.size());
+ return buffer_[(current_pose_index_ - index + buffer_.size()) %
+ buffer_.size()];
+}
+
+} // namespace posepredictor
diff --git a/libs/vr/libposepredictor/dvr_pose_predictor.cpp b/libs/vr/libposepredictor/dvr_pose_predictor.cpp
new file mode 100644
index 0000000..7f2ecc0
--- /dev/null
+++ b/libs/vr/libposepredictor/dvr_pose_predictor.cpp
@@ -0,0 +1,70 @@
+#include <private/dvr/dvr_pose_predictor.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+template <typename Vec3Type>
+float32x4_t FromVec3(const Vec3Type& from) {
+ return {static_cast<float>(from.x()), static_cast<float>(from.y()),
+ static_cast<float>(from.z()), 0};
+}
+
+template <typename QuatType>
+float32x4_t FromQuat(const QuatType& from) {
+ return {static_cast<float>(from.x()), static_cast<float>(from.y()),
+ static_cast<float>(from.z()), static_cast<float>(from.w())};
+}
+
+} // namespace
+
+void AddPredictorPose(posepredictor::Predictor* predictor,
+ const posepredictor::vec3& start_t_head,
+ const posepredictor::quat& start_q_head,
+ int64_t pose_timestamp, DvrPoseAsync* out) {
+ // Feed the predictor.
+ predictor->Add(
+ posepredictor::Pose{pose_timestamp, start_t_head, start_q_head});
+
+ // Fill the output.
+ out->timestamp_ns = pose_timestamp;
+
+ out->translation = FromVec3(start_t_head);
+ out->orientation = FromQuat(start_q_head);
+
+ out->right_translation = out->translation;
+ out->right_orientation = out->orientation;
+
+ const auto velocity = predictor->PredictVelocity(pose_timestamp);
+
+ out->velocity = FromVec3(velocity.linear);
+ out->angular_velocity = FromVec3(velocity.angular);
+
+ out->flags = DVR_POSE_FLAG_HEAD | DVR_POSE_FLAG_VALID;
+ memset(out->pad, 0, sizeof(out->pad));
+}
+
+void PredictPose(const posepredictor::Predictor* predictor, int64_t left_ns,
+ int64_t right_ns, DvrPoseAsync* out) {
+ const auto left_pose = predictor->Predict(left_ns);
+ const auto right_pose = predictor->Predict(right_ns);
+ const auto velocity = predictor->PredictVelocity((left_ns + right_ns) / 2);
+
+ // Fill the output.
+ out->timestamp_ns = left_ns;
+
+ out->translation = FromVec3(left_pose.position);
+ out->orientation = FromQuat(left_pose.orientation);
+
+ out->right_translation = FromVec3(right_pose.position);
+ out->right_orientation = FromQuat(right_pose.orientation);
+
+ out->velocity = FromVec3(velocity.linear);
+ out->angular_velocity = FromVec3(velocity.angular);
+
+ out->flags = DVR_POSE_FLAG_HEAD | DVR_POSE_FLAG_VALID;
+ memset(out->pad, 0, sizeof(out->pad));
+}
+
+} // dvr
+} // android
diff --git a/libs/vr/libposepredictor/include/buffered_predictor.h b/libs/vr/libposepredictor/include/buffered_predictor.h
new file mode 100644
index 0000000..eab0150
--- /dev/null
+++ b/libs/vr/libposepredictor/include/buffered_predictor.h
@@ -0,0 +1,40 @@
+#ifndef POSEPREDICTOR_BUFFERED_PREDICTOR_H_
+#define POSEPREDICTOR_BUFFERED_PREDICTOR_H_
+
+#include <vector>
+
+#include "predictor.h"
+
+namespace posepredictor {
+
+// Keeps the previous n poses around in a ring buffer.
+// The orientations are also unrolled so that a . b > 0 for two subsequent
+// quaternions a and b.
+class BufferedPredictor : public Predictor {
+ public:
+ BufferedPredictor(size_t buffer_size);
+ ~BufferedPredictor() = default;
+
+ protected:
+ // Add a pose sample into the buffer.
+ void BufferSample(const Pose& sample);
+
+ // Grab a previous sample.
+ // index = 0: last sample
+ // index = 1: the one before that
+ // ...
+ const Pose& PrevSample(size_t index) const;
+
+ // Where we keep the last n poses.
+ std::vector<Pose> buffer_;
+
+ // Where the last valid pose is in the buffer.
+ size_t current_pose_index_ = 0;
+
+ // The number of poses we have added.
+ size_t num_poses_added_ = 0;
+};
+
+} // namespace posepredictor
+
+#endif // POSEPREDICTOR_BUFFERED_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/include/linear_predictor.h b/libs/vr/libposepredictor/include/linear_predictor.h
new file mode 100644
index 0000000..0d17ec5
--- /dev/null
+++ b/libs/vr/libposepredictor/include/linear_predictor.h
@@ -0,0 +1,43 @@
+#ifndef POSEPREDICTOR_LINEAR_POSE_PREDICTOR_H_
+#define POSEPREDICTOR_LINEAR_POSE_PREDICTOR_H_
+
+#include "predictor.h"
+
+namespace posepredictor {
+
+// This class makes a linear prediction using the last two samples we received.
+class LinearPosePredictor : public Predictor {
+ public:
+ LinearPosePredictor() = default;
+
+ // Add a new sample.
+ void Add(const Pose& sample) override;
+
+ // Predict using the last two samples.
+ Pose Predict(int64_t time_ns) const override;
+
+ // Just copy the velocity over.
+ Velocity PredictVelocity(int64_t time_ns) const override;
+
+ private:
+ // The index of the last sample we received.
+ size_t current_index_ = 0;
+
+ // The previous two samples.
+ Pose samples_[2];
+
+ // Experimental
+ bool forward_predict_angular_speed_ = false;
+
+ // Transient variables updated when a sample is added.
+ vec3 velocity_ = vec3::Zero();
+ vec3 rotational_velocity_ = vec3::Zero();
+ vec3 rotational_axis_ = vec3::Zero();
+ real last_angular_speed_ = 0;
+ real angular_speed_ = 0;
+ real angular_accel_ = 0;
+};
+
+} // namespace posepredictor
+
+#endif // POSEPREDICTOR_LINEAR_POSE_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/include/polynomial_predictor.h b/libs/vr/libposepredictor/include/polynomial_predictor.h
new file mode 100644
index 0000000..762afd3
--- /dev/null
+++ b/libs/vr/libposepredictor/include/polynomial_predictor.h
@@ -0,0 +1,168 @@
+#ifndef POSEPREDICTOR_POLYNOMIAL_POSE_PREDICTOR_H_
+#define POSEPREDICTOR_POLYNOMIAL_POSE_PREDICTOR_H_
+
+#include <vector>
+
+#include <Eigen/Dense>
+
+#include "buffered_predictor.h"
+
+namespace posepredictor {
+
+// Make a polynomial prediction of the form
+// y = coefficients_[0] + coefficients_[1] * t + coefficients_[2] * t^2 + ...
+// where t is time and y is the position and orientation.
+// We recompute the coefficients whenever we add a new sample using
+// training_window previous samples.
+template <size_t PolynomialDegree, size_t TrainingWindow>
+class PolynomialPosePredictor : public BufferedPredictor {
+ public:
+ PolynomialPosePredictor(real regularization = 1e-9)
+ : BufferedPredictor(TrainingWindow), regularization_(regularization) {
+ static_assert(PolynomialDegree + 1 >= TrainingWindow,
+ "Underconstrained polynomial regressor");
+ }
+
+ ~PolynomialPosePredictor() = default;
+
+ // We convert pose samples into a vector for matrix arithmetic using this
+ // mapping.
+ enum Components {
+ kPositionX = 0,
+ kPositionY,
+ kPositionZ,
+ kOrientationX,
+ kOrientationY,
+ kOrientationZ,
+ kOrientationW,
+ kNumComponents
+ };
+
+ // Add a new sample.
+ void Add(const Pose& sample) override {
+ // Add the sample to the ring buffer.
+ BufferedPredictor::BufferSample(sample);
+
+ Eigen::Matrix<real, TrainingWindow, kNumComponents> values;
+
+ // Get the pose samples into matrices for fitting.
+ real t_vector[TrainingWindow];
+ for (size_t i = 0; i < TrainingWindow; ++i) {
+ const auto& prev_sample = PrevSample(i);
+
+ t_vector[i] = NsToT(prev_sample.time_ns);
+
+ // Save the values we will be fitting to at each sample time.
+ values(i, kPositionX) = prev_sample.position.x();
+ values(i, kPositionY) = prev_sample.position.y();
+ values(i, kPositionZ) = prev_sample.position.z();
+ values(i, kOrientationX) = prev_sample.orientation.x();
+ values(i, kOrientationY) = prev_sample.orientation.y();
+ values(i, kOrientationZ) = prev_sample.orientation.z();
+ values(i, kOrientationW) = prev_sample.orientation.w();
+ }
+
+ // Some transient matrices for solving for coefficient matrix.
+ Eigen::Matrix<real, PolynomialDegree + 1, PolynomialDegree + 1> M;
+ Eigen::Matrix<real, PolynomialDegree + 1, 1> d;
+ Eigen::Matrix<real, PolynomialDegree + 1, 1> p;
+
+ // Create a polynomial fit for each component.
+ for (size_t component = 0; component < kNumComponents; ++component) {
+ // A = [ 1 t t^2 ... ]'
+ // x = [ coefficients[0] coefficients[1] .... ]'
+ // b = [ position.x ]'
+ // We would like to solve A' x + regularization * I = b'
+ // given the samples we have in our training window.
+ //
+ // The loop below will compute:
+ // M = A' * A
+ // d = A' * b
+ // so we can solve M * coefficients + regularization * I = b
+
+ M.setIdentity();
+ d.setZero();
+ p[0] = 1;
+
+ // M = regularization * I
+ M = M * regularization_;
+
+ // Accumulate the poses in the training window.
+ for (size_t i = 0; i < TrainingWindow; ++i) {
+ // Compute the polynomial at this sample.
+ for (size_t j = 1; j <= PolynomialDegree; ++j) {
+ p[j] = p[j - 1] * t_vector[i];
+ }
+
+ // Accumulate the left and right hand sides.
+ M = M + p * p.transpose();
+ d = d + p * values(i, component);
+ }
+
+ // M is symmetric, positive semi-definite.
+ // Note: This is not the most accurate solver out there but is fast.
+ coefficients_.row(component) = Eigen::LLT<Eigen::MatrixXd>(M).solve(d);
+ }
+ }
+
+ // Predict using the polynomial coefficients.
+ Pose Predict(int64_t time_ns) const override {
+ // Predict the left side.
+ const auto components = SamplePolynomial(time_ns);
+
+ return {time_ns,
+ vec3(components[kPositionX], components[kPositionY],
+ components[kPositionZ]),
+ quat(components[kOrientationW], components[kOrientationX],
+ components[kOrientationY], components[kOrientationZ])
+ .normalized()};
+ }
+
+ private:
+ // Evaluate the polynomial at a particular time.
+ Eigen::Matrix<real, kNumComponents, 1> SamplePolynomial(
+ int64_t time_ns) const {
+ const auto t = NsToT(time_ns);
+ Eigen::Matrix<real, PolynomialDegree + 1, 1> polynomial;
+ real current_polynomial = t;
+
+ // Compute polynomial = [ 1 t t^2 ... ]
+ polynomial[0] = 1;
+ for (size_t degree = 1; degree <= PolynomialDegree;
+ ++degree, current_polynomial *= t) {
+ polynomial[degree] = polynomial[degree - 1] * t;
+ }
+
+ // The coefficients_ = [ numComponents x (polynomial degree + 1) ].
+ return coefficients_ * polynomial;
+ }
+
+ // Convert a time in nanoseconds to t.
+ // We could use the seconds as t but this would create make it more difficult
+ // to tweak the regularization amount. So we subtract the last sample time so
+ // the scale of the regularization constant doesn't change as a function of
+ // time.
+ real NsToT(int64_t time_ns) const {
+ return NsToSeconds(time_ns - buffer_[current_pose_index_].time_ns);
+ }
+
+ // The ridge regularization constant.
+ real regularization_;
+
+ // This is where we store the polynomial coefficients.
+ Eigen::Matrix<real, kNumComponents, PolynomialDegree + 1> coefficients_;
+};
+
+// Some common polynomial types.
+extern template class PolynomialPosePredictor<1, 2>;
+extern template class PolynomialPosePredictor<2, 3>;
+extern template class PolynomialPosePredictor<3, 4>;
+extern template class PolynomialPosePredictor<4, 5>;
+
+using QuadricPosePredictor = PolynomialPosePredictor<2, 3>;
+using CubicPosePredictor = PolynomialPosePredictor<3, 4>;
+using QuarticPosePredictor = PolynomialPosePredictor<4, 5>;
+
+} // namespace posepredictor
+
+#endif // POSEPREDICTOR_POLYNOMIAL_POSE_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/include/predictor.h b/libs/vr/libposepredictor/include/predictor.h
new file mode 100644
index 0000000..78db272
--- /dev/null
+++ b/libs/vr/libposepredictor/include/predictor.h
@@ -0,0 +1,73 @@
+#ifndef POSEPREDICTOR_POSE_PREDICTOR_H_
+#define POSEPREDICTOR_POSE_PREDICTOR_H_
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+// This is the only file you need to include for pose prediction.
+
+namespace posepredictor {
+
+// The precision for the predictor.
+// TODO(okana): double precision is probably not necessary.
+typedef double real;
+
+using vec3 = Eigen::Matrix<real, 3, 1>;
+using quat = Eigen::Quaternion<real>;
+
+// Encapsulates a pose sample.
+struct Pose {
+ int64_t time_ns = 0;
+ vec3 position = vec3::Zero();
+ quat orientation = quat::Identity();
+};
+
+// Encapsulates the derivative at a time.
+struct Velocity {
+ vec3 linear = vec3::Zero();
+ vec3 angular = vec3::Zero();
+};
+
+// The preset types we support.
+enum class PredictorType { Linear, Quadric, Cubic };
+
+// This is an abstract base class for prediction 6dof pose given
+// a set of samples.
+class Predictor {
+ public:
+ Predictor() = default;
+ virtual ~Predictor() = default;
+
+ // The nanoseconds to use for finite differencing.
+ static constexpr int64_t kFiniteDifferenceNs = 100;
+
+ // Instantiate a new pose predictor for a type.
+ static std::unique_ptr<Predictor> Create(PredictorType type);
+
+ // Compute the angular velocity from orientation start_orientation to
+ // end_orientation in delta_time.
+ static vec3 AngularVelocity(const quat& start_orientation,
+ const quat& end_orientation, real delta_time);
+
+ // Add a pose sample coming from the sensors.
+ virtual void Add(const Pose& sample) = 0;
+
+ // Make a pose prediction for at specific time.
+ virtual Pose Predict(int64_t time_ns) const = 0;
+
+ // Evaluate velocity at a particular time.
+ // The default implementation uses finite differencing.
+ virtual Velocity PredictVelocity(int64_t time_ns) const;
+
+ // Helpers
+ static real NsToSeconds(int64_t time_ns) {
+ return static_cast<real>(time_ns / 1e9);
+ }
+ static int64_t SecondsToNs(real seconds) {
+ return static_cast<int64_t>(seconds * 1e9);
+ }
+};
+
+} // namespace posepredictor
+
+#endif // POSEPREDICTOR_POSE_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/include/private/dvr/dvr_pose_predictor.h b/libs/vr/libposepredictor/include/private/dvr/dvr_pose_predictor.h
new file mode 100644
index 0000000..bd2dcbc
--- /dev/null
+++ b/libs/vr/libposepredictor/include/private/dvr/dvr_pose_predictor.h
@@ -0,0 +1,25 @@
+#ifndef ANDROID_DVR_POSE_PREDICTOR_H_
+#define ANDROID_DVR_POSE_PREDICTOR_H_
+
+#include <dvr/pose_client.h>
+#include <predictor.h>
+
+// Some shim functions for connecting dvr to pose predictor.
+
+namespace android {
+namespace dvr {
+
+// Feed a pose to the predictor.
+void AddPredictorPose(posepredictor::Predictor* predictor,
+ const posepredictor::vec3& start_t_head,
+ const posepredictor::quat& start_q_head,
+ int64_t pose_timestamp, DvrPoseAsync* out);
+
+// Make a prediction for left and right eyes.
+void PredictPose(const posepredictor::Predictor* predictor, int64_t left_ns,
+ int64_t right_ns, DvrPoseAsync* out);
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_POSE_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/include/private/dvr/linear_pose_predictor.h b/libs/vr/libposepredictor/include/private/dvr/linear_pose_predictor.h
deleted file mode 100644
index 1efe938..0000000
--- a/libs/vr/libposepredictor/include/private/dvr/linear_pose_predictor.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_DVR_POSE_PREDICTOR_H_
-#define ANDROID_DVR_POSE_PREDICTOR_H_
-
-#include <private/dvr/pose_predictor.h>
-
-namespace android {
-namespace dvr {
-
-// This class makes a linear prediction using the last two samples we received.
-class LinearPosePredictor : public PosePredictor {
- public:
- LinearPosePredictor() = default;
-
- // Add a new sample.
- void Add(const Sample& sample, DvrPoseAsync* out_pose) override;
-
- // Predict using the last two samples.
- void Predict(int64_t left_time_ns, int64_t right_time_ns,
- DvrPoseAsync* out_pose) const override;
-
- private:
- // The index of the last sample we received.
- size_t current_index_ = 0;
-
- // The previous two samples.
- Sample samples_[2];
-
- // Experimental
- bool forward_predict_angular_speed_ = false;
-
- // Transient variables updated when a sample is added.
- vec3d velocity_ = vec3d::Zero();
- vec3d rotational_velocity_ = vec3d::Zero();
- vec3d rotational_axis_ = vec3d::Zero();
- double last_angular_speed_ = 0;
- double angular_speed_ = 0;
- double angular_accel_ = 0;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_POSE_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/include/private/dvr/pose_predictor.h b/libs/vr/libposepredictor/include/private/dvr/pose_predictor.h
deleted file mode 100644
index 719edbe..0000000
--- a/libs/vr/libposepredictor/include/private/dvr/pose_predictor.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef ANDROID_DVR_LINEAR_POSE_PREDICTOR_H_
-#define ANDROID_DVR_LINEAR_POSE_PREDICTOR_H_
-
-#include <private/dvr/pose_client_internal.h>
-#include <private/dvr/types.h>
-
-namespace android {
-namespace dvr {
-
-// This is an abstract base class for prediction 6dof pose given
-// a set of samples.
-//
-// TODO(okana): Create a framework for testing different subclasses for
-// performance and accuracy.
-class PosePredictor {
- public:
- PosePredictor() = default;
- virtual ~PosePredictor() = default;
-
- // Encapsulates a pose sample.
- struct Sample {
- vec3d position = vec3d::Zero();
- quatd orientation = quatd::Identity();
- int64_t time_ns = 0;
- };
-
- // Add a pose sample coming from the sensors.
- // Returns this sample as a dvr pose.
- //
- // We will use the returned pose if prediction is not enabled.
- virtual void Add(const Sample& sample, DvrPoseAsync* out_pose) = 0;
-
- // Make a pose prediction for the left and right eyes at specific times.
- virtual void Predict(int64_t left_time_ns, int64_t right_time_ns,
- DvrPoseAsync* out_pose) const = 0;
-
- // Helpers
- static double NsToSeconds(int64_t time_ns) { return time_ns / 1e9; }
- static int64_t SecondsToNs(double seconds) {
- return static_cast<int64_t>(seconds * 1e9);
- }
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_LINEAR_POSE_PREDICTOR_H_
diff --git a/libs/vr/libposepredictor/linear_pose_predictor.cpp b/libs/vr/libposepredictor/linear_pose_predictor.cpp
deleted file mode 100644
index de1b951..0000000
--- a/libs/vr/libposepredictor/linear_pose_predictor.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-#include <log/log.h>
-
-#include <private/dvr/linear_pose_predictor.h>
-
-namespace android {
-namespace dvr {
-
-using AngleAxisd = Eigen::AngleAxis<double>;
-
-void LinearPosePredictor::Add(const Sample& sample, DvrPoseAsync* out_pose) {
- // If we are receiving a new sample, move the index to the next item.
- // If the time stamp is the same as the last frame, we will just overwrite
- // it with the new data.
- if (sample.time_ns != samples_[current_index_].time_ns) {
- current_index_ ^= 1;
- }
-
- // Save the sample.
- samples_[current_index_] = sample;
-
- // The previous sample we received.
- const auto& previous_sample = samples_[current_index_ ^ 1];
-
- // Ready to compute velocities.
- const auto pose_delta_time =
- NsToSeconds(sample.time_ns - previous_sample.time_ns);
-
- const double inverse_dt = 1. / pose_delta_time;
- if (pose_delta_time > 0.0) {
- velocity_ = (sample.position - previous_sample.position) * inverse_dt;
- } else {
- velocity_ = vec3d::Zero();
- }
-
- quatd delta_q = sample.orientation.inverse() * previous_sample.orientation;
- // Check that delta_q.w() == 1, Eigen doesn't respect this convention. If
- // delta_q.w() == -1, we'll get the opposite velocity.
- if (delta_q.w() < 0) {
- delta_q.w() = -delta_q.w();
- delta_q.vec() = -delta_q.vec();
- }
- rotational_velocity_ = -2.0 * delta_q.vec() * inverse_dt;
-
- // Temporary experiment with acceleration estimate.
- angular_speed_ = rotational_velocity_.norm();
- angular_accel_ = 0.0;
- if (forward_predict_angular_speed_) {
- angular_accel_ =
- pose_delta_time > 0.0
- ? (angular_speed_ - last_angular_speed_) / pose_delta_time
- : 0.0;
- }
- last_angular_speed_ = angular_speed_;
-
- rotational_axis_ = vec3d(0.0, 1.0, 0.0);
- if (angular_speed_ > 0.0) {
- rotational_axis_ = rotational_velocity_ / angular_speed_;
- }
-
- out_pose->orientation = {static_cast<float>(sample.orientation.vec().x()),
- static_cast<float>(sample.orientation.vec().y()),
- static_cast<float>(sample.orientation.vec().z()),
- static_cast<float>(sample.orientation.w())};
-
- out_pose->translation = {static_cast<float>(sample.position.x()),
- static_cast<float>(sample.position.y()),
- static_cast<float>(sample.position.z()), 0.0f};
-
- out_pose->right_orientation = {
- static_cast<float>(sample.orientation.vec().x()),
- static_cast<float>(sample.orientation.vec().y()),
- static_cast<float>(sample.orientation.vec().z()),
- static_cast<float>(sample.orientation.w())};
-
- out_pose->right_translation = {static_cast<float>(sample.position.x()),
- static_cast<float>(sample.position.y()),
- static_cast<float>(sample.position.z()), 0.0f};
-
- out_pose->angular_velocity = {static_cast<float>(rotational_velocity_.x()),
- static_cast<float>(rotational_velocity_.y()),
- static_cast<float>(rotational_velocity_.z()),
- 0.0f};
-
- out_pose->velocity = {static_cast<float>(velocity_.x()),
- static_cast<float>(velocity_.y()),
- static_cast<float>(velocity_.z()), 0.0f};
- out_pose->timestamp_ns = sample.time_ns;
- out_pose->flags = DVR_POSE_FLAG_HEAD | DVR_POSE_FLAG_VALID;
- memset(out_pose->pad, 0, sizeof(out_pose->pad));
-}
-
-void LinearPosePredictor::Predict(int64_t left_time_ns, int64_t right_time_ns,
- DvrPoseAsync* out_pose) const {
- const auto& sample = samples_[current_index_];
-
- double dt = NsToSeconds(left_time_ns - sample.time_ns);
- double r_dt = NsToSeconds(right_time_ns - sample.time_ns);
-
- // Temporary forward prediction code.
- auto start_t_head_future = sample.position + velocity_ * dt;
- auto r_start_t_head_future = sample.position + velocity_ * r_dt;
- double angle = angular_speed_ * dt;
- double r_angle = angular_speed_ * r_dt;
- if (__builtin_expect(forward_predict_angular_speed_, 0)) {
- angle += 0.5 * angular_accel_ * dt * dt;
- r_angle += 0.5 * angular_accel_ * r_dt * r_dt;
- }
- auto start_q_head_future =
- sample.orientation * quatd(AngleAxisd(angle, rotational_axis_));
- auto r_start_q_head_future =
- sample.orientation * quatd(AngleAxisd(r_angle, rotational_axis_));
-
- out_pose->orientation = {static_cast<float>(start_q_head_future.x()),
- static_cast<float>(start_q_head_future.y()),
- static_cast<float>(start_q_head_future.z()),
- static_cast<float>(start_q_head_future.w())};
-
- out_pose->translation = {static_cast<float>(start_t_head_future.x()),
- static_cast<float>(start_t_head_future.y()),
- static_cast<float>(start_t_head_future.z()), 0.0f};
-
- out_pose->right_orientation = {static_cast<float>(r_start_q_head_future.x()),
- static_cast<float>(r_start_q_head_future.y()),
- static_cast<float>(r_start_q_head_future.z()),
- static_cast<float>(r_start_q_head_future.w())};
-
- out_pose->right_translation = {static_cast<float>(r_start_t_head_future.x()),
- static_cast<float>(r_start_t_head_future.y()),
- static_cast<float>(r_start_t_head_future.z()),
- 0.0f};
-
- out_pose->angular_velocity = {static_cast<float>(rotational_velocity_.x()),
- static_cast<float>(rotational_velocity_.y()),
- static_cast<float>(rotational_velocity_.z()),
- 0.0f};
-
- out_pose->velocity = {static_cast<float>(velocity_.x()),
- static_cast<float>(velocity_.y()),
- static_cast<float>(velocity_.z()), 0.0f};
-
- out_pose->timestamp_ns = left_time_ns;
- out_pose->flags = DVR_POSE_FLAG_HEAD | DVR_POSE_FLAG_VALID;
- memset(out_pose->pad, 0, sizeof(out_pose->pad));
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libposepredictor/linear_pose_predictor_tests.cpp b/libs/vr/libposepredictor/linear_pose_predictor_tests.cpp
deleted file mode 100644
index 6c4f58a..0000000
--- a/libs/vr/libposepredictor/linear_pose_predictor_tests.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <private/dvr/linear_pose_predictor.h>
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-// For comparing expected and actual.
-constexpr double kAbsErrorTolerance = 1e-5;
-
-// The default rotation axis we will be using.
-const vec3d kRotationAxis = vec3d(1, 4, 3).normalized();
-
-// Linearly interpolate between a and b.
-vec3d lerp(const vec3d& a, const vec3d& b, double t) { return (b - a) * t + a; }
-
-// Linearly interpolate between two angles and return the resulting rotation as
-// a quaternion (around the kRotationAxis).
-quatd qlerp(double angle1, double angle2, double t) {
- return quatd(
- Eigen::AngleAxis<double>((angle2 - angle1) * t + angle1, kRotationAxis));
-}
-
-// Compare two positions.
-void TestPosition(const vec3d& expected, const float32x4_t& actual) {
- for (int i = 0; i < 3; ++i) {
- EXPECT_NEAR(expected[i], static_cast<double>(actual[i]),
- kAbsErrorTolerance);
- }
-}
-
-// Compare two orientations.
-void TestOrientation(const quatd& expected, const float32x4_t& actual) {
- // abs(expected.dot(actual)) > 1-eps
- EXPECT_GE(std::abs(vec4d(actual[0], actual[1], actual[2], actual[3])
- .dot(expected.coeffs())),
- 0.99);
-}
-}
-
-// Test the extrapolation from two samples.
-TEST(LinearPosePredictorTest, Extrapolation) {
- LinearPosePredictor predictor;
-
- // We wil extrapolate linearly from [position|orientation] 1 -> 2.
- const vec3d position1(0, 0, 0);
- const vec3d position2(1, 2, 3);
- const double angle1 = M_PI * 0.3;
- const double angle2 = M_PI * 0.5;
- const quatd orientation1(Eigen::AngleAxis<double>(angle1, kRotationAxis));
- const quatd orientation2(Eigen::AngleAxis<double>(angle2, kRotationAxis));
- const int64_t t1_ns = 0; //< First sample time stamp
- const int64_t t2_ns = 10; //< The second sample time stamp
- const int64_t eval_left_ns = 23; //< The eval time for left
- const int64_t eval_right_ns = 31; //< The eval time for right
- DvrPoseAsync start_pose, end_pose, extrapolated_pose;
-
- predictor.Add(
- PosePredictor::Sample{
- .position = position1, .orientation = orientation1, .time_ns = t1_ns},
- &start_pose);
-
- // The start pose is passthough.
- TestPosition(position1, start_pose.translation);
- TestPosition(position1, start_pose.right_translation);
- TestOrientation(orientation1, start_pose.orientation);
- TestOrientation(orientation1, start_pose.right_orientation);
- EXPECT_EQ(t1_ns, start_pose.timestamp_ns);
-
- predictor.Add(
- PosePredictor::Sample{
- .position = position2, .orientation = orientation2, .time_ns = t2_ns},
- &end_pose);
-
- TestPosition(position2, end_pose.translation);
- TestPosition(position2, end_pose.right_translation);
- TestOrientation(orientation2, end_pose.orientation);
- TestOrientation(orientation2, end_pose.right_orientation);
- EXPECT_EQ(t2_ns, end_pose.timestamp_ns);
-
- // Extrapolate from t1 - t2 to eval_[left/right].
- predictor.Predict(eval_left_ns, eval_right_ns, &extrapolated_pose);
-
- // The interpolation factors for left and right.
- const auto left_t =
- (eval_left_ns - t1_ns) / static_cast<double>(t2_ns - t1_ns);
- EXPECT_EQ(2.3, left_t);
-
- const auto right_t =
- (eval_right_ns - t1_ns) / static_cast<double>(t2_ns - t1_ns);
- EXPECT_EQ(3.1, right_t);
-
- TestPosition(lerp(position1, position2, left_t),
- extrapolated_pose.translation);
- TestPosition(lerp(position1, position2, right_t),
- extrapolated_pose.right_translation);
- TestOrientation(qlerp(angle1, angle2, left_t), extrapolated_pose.orientation);
- TestOrientation(qlerp(angle1, angle2, right_t),
- extrapolated_pose.right_orientation);
-}
-
-// Test three samples, where the last two samples have the same timestamp.
-TEST(LinearPosePredictorTest, DuplicateSamples) {
- LinearPosePredictor predictor;
-
- const vec3d position1(0, 0, 0);
- const vec3d position2(1, 2, 3);
- const vec3d position3(2, 2, 3);
- const double angle1 = M_PI * 0.3;
- const double angle2 = M_PI * 0.5;
- const double angle3 = M_PI * 0.65;
- const quatd orientation1(Eigen::AngleAxis<double>(angle1, kRotationAxis));
- const quatd orientation2(Eigen::AngleAxis<double>(angle2, kRotationAxis));
- const quatd orientation3(Eigen::AngleAxis<double>(angle3, kRotationAxis));
- const int64_t t1_ns = 0;
- const int64_t t2_ns = 10;
- const int64_t eval_left_ns = 27;
- const int64_t eval_right_ns = 31;
- DvrPoseAsync start_pose, end_pose, extrapolated_pose;
-
- predictor.Add(
- PosePredictor::Sample{
- .position = position1, .orientation = orientation1, .time_ns = t1_ns},
- &start_pose);
-
- predictor.Add(
- PosePredictor::Sample{
- .position = position2, .orientation = orientation2, .time_ns = t2_ns},
- &end_pose);
-
- {
- // Extrapolate from t1 - t2 to eval_[left/right].
- predictor.Predict(eval_left_ns, eval_right_ns, &extrapolated_pose);
-
- // The interpolation factors for left and right.
- const auto left_t =
- (eval_left_ns - t1_ns) / static_cast<double>(t2_ns - t1_ns);
- const auto right_t =
- (eval_right_ns - t1_ns) / static_cast<double>(t2_ns - t1_ns);
-
- // Test the result.
- TestPosition(lerp(position1, position2, left_t),
- extrapolated_pose.translation);
- TestPosition(lerp(position1, position2, right_t),
- extrapolated_pose.right_translation);
- TestOrientation(qlerp(angle1, angle2, left_t),
- extrapolated_pose.orientation);
- TestOrientation(qlerp(angle1, angle2, right_t),
- extrapolated_pose.right_orientation);
- }
-
- // Sending a duplicate sample here.
- predictor.Add(
- PosePredictor::Sample{
- .position = position3, .orientation = orientation3, .time_ns = t2_ns},
- &end_pose);
-
- {
- // Extrapolate from t1 - t2 to eval_[left/right].
- predictor.Predict(eval_left_ns, eval_right_ns, &extrapolated_pose);
-
- // The interpolation factors for left and right.
- const auto left_t =
- (eval_left_ns - t1_ns) / static_cast<double>(t2_ns - t1_ns);
- const auto right_t =
- (eval_right_ns - t1_ns) / static_cast<double>(t2_ns - t1_ns);
-
- // Test the result.
- TestPosition(lerp(position1, position3, left_t),
- extrapolated_pose.translation);
- TestPosition(lerp(position1, position3, right_t),
- extrapolated_pose.right_translation);
- TestOrientation(qlerp(angle1, angle3, left_t),
- extrapolated_pose.orientation);
- TestOrientation(qlerp(angle1, angle3, right_t),
- extrapolated_pose.right_orientation);
- }
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libposepredictor/linear_predictor.cpp b/libs/vr/libposepredictor/linear_predictor.cpp
new file mode 100644
index 0000000..6f924dc
--- /dev/null
+++ b/libs/vr/libposepredictor/linear_predictor.cpp
@@ -0,0 +1,70 @@
+#include <linear_predictor.h>
+
+namespace posepredictor {
+
+using AngleAxis = Eigen::AngleAxis<real>;
+
+void LinearPosePredictor::Add(const Pose& sample) {
+ // If we are receiving a new sample, move the index to the next item.
+ // If the time stamp is the same as the last frame, we will just overwrite
+ // it with the new data.
+ if (sample.time_ns != samples_[current_index_].time_ns) {
+ current_index_ ^= 1;
+ }
+
+ // Save the sample.
+ samples_[current_index_] = sample;
+
+ // The previous sample we received.
+ const auto& previous_sample = samples_[current_index_ ^ 1];
+
+ // Ready to compute velocities.
+ const auto pose_delta_time =
+ NsToSeconds(sample.time_ns - previous_sample.time_ns);
+
+ if (pose_delta_time > 0.0) {
+ velocity_ = (sample.position - previous_sample.position) / pose_delta_time;
+ rotational_velocity_ = Predictor::AngularVelocity(
+ previous_sample.orientation, sample.orientation, pose_delta_time);
+ } else {
+ velocity_ = vec3::Zero();
+ rotational_velocity_ = vec3::Zero();
+ }
+
+ // Temporary experiment with acceleration estimate.
+ angular_speed_ = rotational_velocity_.norm();
+ angular_accel_ = 0.0;
+ if (forward_predict_angular_speed_) {
+ angular_accel_ =
+ pose_delta_time > 0.0
+ ? (angular_speed_ - last_angular_speed_) / pose_delta_time
+ : 0.0;
+ }
+ last_angular_speed_ = angular_speed_;
+
+ rotational_axis_ = vec3(0.0, 1.0, 0.0);
+ if (angular_speed_ > 0.0) {
+ rotational_axis_ = rotational_velocity_ / angular_speed_;
+ }
+}
+
+Pose LinearPosePredictor::Predict(int64_t time_ns) const {
+ const auto& sample = samples_[current_index_];
+
+ const auto dt = NsToSeconds(time_ns - sample.time_ns);
+
+ // Temporary forward prediction code.
+ auto angle = angular_speed_ * dt;
+ if (__builtin_expect(forward_predict_angular_speed_, 0)) {
+ angle += 0.5 * angular_accel_ * dt * dt;
+ }
+
+ return {time_ns, sample.position + velocity_ * dt,
+ sample.orientation * quat(AngleAxis(angle, rotational_axis_))};
+}
+
+Velocity LinearPosePredictor::PredictVelocity(int64_t /* time_ns */) const {
+ return {velocity_, rotational_velocity_};
+}
+
+} // namespace posepredictor
diff --git a/libs/vr/libposepredictor/linear_predictor_tests.cpp b/libs/vr/libposepredictor/linear_predictor_tests.cpp
new file mode 100644
index 0000000..d94aa2d
--- /dev/null
+++ b/libs/vr/libposepredictor/linear_predictor_tests.cpp
@@ -0,0 +1,170 @@
+#include <gtest/gtest.h>
+
+#include <linear_predictor.h>
+
+namespace posepredictor {
+
+namespace {
+
+// For comparing expected and actual.
+constexpr real kAbsErrorTolerance = 1e-5;
+
+// The default rotation axis we will be using.
+const vec3 kRotationAxis = vec3(1, 4, 3).normalized();
+
+// Linearly interpolate between a and b.
+vec3 lerp(const vec3& a, const vec3& b, real t) { return (b - a) * t + a; }
+
+// Linearly interpolate between two angles and return the resulting rotation as
+// a quaternion (around the kRotationAxis).
+quat qlerp(real angle1, real angle2, real t) {
+ return quat(
+ Eigen::AngleAxis<real>((angle2 - angle1) * t + angle1, kRotationAxis));
+}
+
+// Compare two positions.
+void TestPosition(const vec3& expected, const vec3& actual) {
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_NEAR(expected[i], actual[i], kAbsErrorTolerance);
+ }
+}
+
+// Compare two orientations.
+void TestOrientation(const quat& expected, const quat& actual) {
+ // abs(expected.dot(actual)) > 1-eps
+ EXPECT_GE(std::abs(actual.coeffs().dot(expected.coeffs())), 0.99);
+}
+}
+
+// Test the extrapolation from two samples.
+TEST(LinearPosePredictorTest, Extrapolation) {
+ LinearPosePredictor predictor;
+
+ // We wil extrapolate linearly from [position|orientation] 1 -> 2.
+ const vec3 position1(0, 0, 0);
+ const vec3 position2(1, 2, 3);
+ const real angle1 = M_PI * 0.3;
+ const real angle2 = M_PI * 0.5;
+ const quat orientation1(Eigen::AngleAxis<real>(angle1, kRotationAxis));
+ const quat orientation2(Eigen::AngleAxis<real>(angle2, kRotationAxis));
+ const int64_t t1_ns = 0; //< First sample time stamp
+ const int64_t t2_ns = 10; //< The second sample time stamp
+ const int64_t eval_left_ns = 23; //< The eval time for left
+ const int64_t eval_right_ns = 31; //< The eval time for right
+ Pose start_pose, end_pose, extrapolated_pose;
+
+ predictor.Add(Pose{
+ .position = position1, .orientation = orientation1, .time_ns = t1_ns});
+
+ predictor.Add(Pose{
+ .position = position2, .orientation = orientation2, .time_ns = t2_ns});
+
+ // Extrapolate from t1 - t2 to eval_[left/right].
+ extrapolated_pose = predictor.Predict(eval_left_ns);
+
+ // The interpolation factors for left and right.
+ const auto left_t = (eval_left_ns - t1_ns) / static_cast<real>(t2_ns - t1_ns);
+ EXPECT_EQ(2.3, left_t);
+
+ TestPosition(lerp(position1, position2, left_t), extrapolated_pose.position);
+
+ TestOrientation(qlerp(angle1, angle2, left_t), extrapolated_pose.orientation);
+
+ extrapolated_pose = predictor.Predict(eval_right_ns);
+
+ const auto right_t =
+ (eval_right_ns - t1_ns) / static_cast<real>(t2_ns - t1_ns);
+ EXPECT_EQ(3.1, right_t);
+
+ TestPosition(lerp(position1, position2, right_t), extrapolated_pose.position);
+
+ TestOrientation(qlerp(angle1, angle2, right_t),
+ extrapolated_pose.orientation);
+}
+
+// Test three samples, where the last two samples have the same timestamp.
+TEST(LinearPosePredictorTest, DuplicateSamples) {
+ LinearPosePredictor predictor;
+
+ const vec3 position1(0, 0, 0);
+ const vec3 position2(1, 2, 3);
+ const vec3 position3(2, 2, 3);
+ const real angle1 = M_PI * 0.3;
+ const real angle2 = M_PI * 0.5;
+ const real angle3 = M_PI * 0.65;
+ const quat orientation1(Eigen::AngleAxis<real>(angle1, kRotationAxis));
+ const quat orientation2(Eigen::AngleAxis<real>(angle2, kRotationAxis));
+ const quat orientation3(Eigen::AngleAxis<real>(angle3, kRotationAxis));
+ const int64_t t1_ns = 0;
+ const int64_t t2_ns = 10;
+ const int64_t eval_left_ns = 27;
+ const int64_t eval_right_ns = 31;
+ Pose extrapolated_pose;
+
+ predictor.Add(Pose{
+ .position = position1, .orientation = orientation1, .time_ns = t1_ns});
+
+ predictor.Add(Pose{
+ .position = position2, .orientation = orientation2, .time_ns = t2_ns});
+
+ {
+ // Extrapolate from t1 - t2 to eval_[left/right].
+ extrapolated_pose = predictor.Predict(eval_left_ns);
+
+ // The interpolation factors for left and right.
+ const auto left_t =
+ (eval_left_ns - t1_ns) / static_cast<real>(t2_ns - t1_ns);
+
+ // Test the result.
+ TestPosition(lerp(position1, position2, left_t),
+ extrapolated_pose.position);
+
+ TestOrientation(qlerp(angle1, angle2, left_t),
+ extrapolated_pose.orientation);
+
+ extrapolated_pose = predictor.Predict(eval_right_ns);
+
+ const auto right_t =
+ (eval_right_ns - t1_ns) / static_cast<real>(t2_ns - t1_ns);
+
+ TestPosition(lerp(position1, position2, right_t),
+ extrapolated_pose.position);
+
+ TestOrientation(qlerp(angle1, angle2, right_t),
+ extrapolated_pose.orientation);
+ }
+
+ // Sending a duplicate sample here.
+ predictor.Add(Pose{
+ .position = position3, .orientation = orientation3, .time_ns = t2_ns});
+
+ {
+ // Extrapolate from t1 - t2 to eval_[left/right].
+ extrapolated_pose = predictor.Predict(eval_left_ns);
+
+ // The interpolation factors for left and right.
+ const auto left_t =
+ (eval_left_ns - t1_ns) / static_cast<real>(t2_ns - t1_ns);
+
+ TestPosition(lerp(position1, position3, left_t),
+ extrapolated_pose.position);
+
+ TestOrientation(qlerp(angle1, angle3, left_t),
+ extrapolated_pose.orientation);
+
+ extrapolated_pose = predictor.Predict(eval_right_ns);
+
+ const auto right_t =
+ (eval_right_ns - t1_ns) / static_cast<real>(t2_ns - t1_ns);
+
+ // Test the result.
+
+ TestPosition(lerp(position1, position3, right_t),
+ extrapolated_pose.position);
+
+ TestOrientation(qlerp(angle1, angle3, right_t),
+ extrapolated_pose.orientation);
+ }
+}
+
+} // namespace posepredictor
diff --git a/libs/vr/libposepredictor/polynomial_predictor.cpp b/libs/vr/libposepredictor/polynomial_predictor.cpp
new file mode 100644
index 0000000..98fd28a
--- /dev/null
+++ b/libs/vr/libposepredictor/polynomial_predictor.cpp
@@ -0,0 +1,11 @@
+#include <polynomial_predictor.h>
+
+namespace posepredictor {
+
+// Instantiate the common polynomial types.
+template class PolynomialPosePredictor<1, 2>;
+template class PolynomialPosePredictor<2, 3>;
+template class PolynomialPosePredictor<3, 4>;
+template class PolynomialPosePredictor<4, 5>;
+
+} // namespace posepredictor
diff --git a/libs/vr/libposepredictor/polynomial_predictor_tests.cpp b/libs/vr/libposepredictor/polynomial_predictor_tests.cpp
new file mode 100644
index 0000000..88cb2b9
--- /dev/null
+++ b/libs/vr/libposepredictor/polynomial_predictor_tests.cpp
@@ -0,0 +1,120 @@
+#include <gtest/gtest.h>
+
+#include <polynomial_predictor.h>
+
+namespace posepredictor {
+
+namespace {
+
+// For comparing expected and actual.
+constexpr real kAbsErrorTolerance = 1e-5;
+
+// Test the linear extrapolation from two samples.
+TEST(PolynomialPosePredictor, Linear) {
+ // Degree = 1, simple line, passing through two points.
+ // Note the regularization is 0 so we expect the exact fit.
+ PolynomialPosePredictor<1, 2> predictor(0);
+
+ // Add two samples.
+ predictor.Add(
+ Pose{.position = {0, 0, 0}, .orientation = {0, 0, 0, 1}, .time_ns = 0});
+
+ predictor.Add(
+ Pose{.position = {1, 2, 3}, .orientation = {0, 0, 0, 1}, .time_ns = 10});
+
+ Pose predicted_pose;
+
+ predicted_pose = predictor.Predict(20);
+
+ // Check the x,y,z components for the expected translation.
+ EXPECT_NEAR(predicted_pose.position[0], 2, kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[1], 4, kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[2], 6, kAbsErrorTolerance);
+
+ predicted_pose = predictor.Predict(30);
+ EXPECT_NEAR(predicted_pose.position[0], 3, kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[1], 6, kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[2], 9, kAbsErrorTolerance);
+}
+
+// Test the degree two polynomial fit.
+TEST(PolynomialPosePredictor, Quadric) {
+ // Degree = 2, need three samples to fit a polynomial.
+ // Note the regularization is 0 so we expect the exact fit.
+ PolynomialPosePredictor<2, 3> predictor(0);
+
+ // Add three samples.
+ predictor.Add(
+ Pose{.position = {1, 2, 3}, .orientation = {0, 0, 0, 1}, .time_ns = 0});
+
+ predictor.Add(
+ Pose{.position = {0, 0, 0}, .orientation = {0, 0, 0, 1}, .time_ns = 10});
+
+ predictor.Add(
+ Pose{.position = {1, 2, 3}, .orientation = {0, 0, 0, 1}, .time_ns = 20});
+
+ // The expected polynomials for x/y/z.
+
+ // x: 0.01 * t^2 - 0.2 * t + 1
+ const auto x = [](auto t) { return 0.01 * t * t - 0.2 * t + 1; };
+
+ // y: 0.02 * t^2 - 0.4 * t + 2
+ const auto y = [](auto t) { return 0.02 * t * t - 0.4 * t + 2; };
+
+ // z: 0.03 * t^2 - 0.6 * t + 3
+ const auto z = [](auto t) { return 0.03 * t * t - 0.6 * t + 3; };
+
+ Pose predicted_pose;
+ predicted_pose = predictor.Predict(40);
+
+ // Check the x,y,z components for the expected translation.
+ EXPECT_NEAR(predicted_pose.position[0], x(40), kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[1], y(40), kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[2], z(40), kAbsErrorTolerance);
+
+ predicted_pose = predictor.Predict(50);
+ EXPECT_NEAR(predicted_pose.position[0], x(50), kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[1], y(50), kAbsErrorTolerance);
+ EXPECT_NEAR(predicted_pose.position[2], z(50), kAbsErrorTolerance);
+}
+
+// Test the degree two polynomial fit with degenerate input.
+//
+// The input samples all lie in a line which would normally make our system
+// degenerate. We will rely on the regularization term to recover the linear
+// solution in a quadric predictor.
+TEST(PolynomialPosePredictor, QuadricDegenate) {
+ // Degree = 2, need three samples to fit a polynomial.
+ // Note that we are using the default regularization term here.
+ // We cannot use 0 regularizer since the input is degenerate.
+ PolynomialPosePredictor<2, 3> predictor(1e-20);
+
+ // Add three samples.
+ predictor.Add(
+ Pose{.position = {0, 0, 0}, .orientation = {0, 0, 0, 1}, .time_ns = 0});
+
+ predictor.Add(
+ Pose{.position = {1, 2, 3}, .orientation = {0, 0, 0, 1}, .time_ns = 10});
+
+ predictor.Add(
+ Pose{.position = {2, 4, 6}, .orientation = {0, 0, 0, 1}, .time_ns = 20});
+
+ Pose predicted_pose;
+
+ predicted_pose = predictor.Predict(30);
+
+ // Check the x,y,z components for the expected translation.
+ // We are using a higher error threshold since this is now approximate.
+ EXPECT_NEAR(predicted_pose.position[0], 3, 0.001);
+ EXPECT_NEAR(predicted_pose.position[1], 6, 0.001);
+ EXPECT_NEAR(predicted_pose.position[2], 9, 0.001);
+
+ predicted_pose = predictor.Predict(40);
+ EXPECT_NEAR(predicted_pose.position[0], 4, 0.001);
+ EXPECT_NEAR(predicted_pose.position[1], 8, 0.001);
+ EXPECT_NEAR(predicted_pose.position[2], 12, 0.001);
+}
+
+} // namespace
+
+} // namespace posepredictor
diff --git a/libs/vr/libposepredictor/predictor.cpp b/libs/vr/libposepredictor/predictor.cpp
new file mode 100644
index 0000000..266e7ef
--- /dev/null
+++ b/libs/vr/libposepredictor/predictor.cpp
@@ -0,0 +1,34 @@
+#include <linear_predictor.h>
+#include <polynomial_predictor.h>
+#include <predictor.h>
+
+namespace posepredictor {
+
+vec3 Predictor::AngularVelocity(const quat& a, const quat& b, real delta_time) {
+ const auto delta_q = b.inverse() * a;
+ // Check that delta_q.w() == 1, Eigen doesn't respect this convention. If
+ // delta_q.w() == -1, we'll get the opposite velocity.
+ return 2.0 * (delta_q.w() < 0 ? -delta_q.vec() : delta_q.vec()) / delta_time;
+}
+
+Velocity Predictor::PredictVelocity(int64_t time_ns) const {
+ const auto a = Predict(time_ns - kFiniteDifferenceNs);
+ const auto b = Predict(time_ns + kFiniteDifferenceNs);
+ const auto delta_time = NsToSeconds(2 * kFiniteDifferenceNs);
+
+ return {(b.position - a.position) / delta_time,
+ AngularVelocity(a.orientation, b.orientation, delta_time)};
+}
+
+// The factory method.
+std::unique_ptr<Predictor> Predictor::Create(PredictorType type) {
+ switch (type) {
+ case PredictorType::Linear:
+ return std::make_unique<LinearPosePredictor>();
+ case PredictorType::Quadric:
+ return std::make_unique<QuadricPosePredictor>();
+ case PredictorType::Cubic:
+ return std::make_unique<CubicPosePredictor>();
+ }
+}
+} // namespace posepredictor
diff --git a/libs/vr/libposepredictor/predictor_tests.cpp b/libs/vr/libposepredictor/predictor_tests.cpp
new file mode 100644
index 0000000..e84a93a
--- /dev/null
+++ b/libs/vr/libposepredictor/predictor_tests.cpp
@@ -0,0 +1,50 @@
+#include <gtest/gtest.h>
+
+#include <predictor.h>
+
+namespace posepredictor {
+
+namespace {
+
+// For comparing expected and actual.
+constexpr real kAbsErrorTolerance = 1e-4;
+
+// Test the angular velocity computation from two orientations.
+TEST(PosePredictor, AngularVelocity) {
+ // Some random rotation axis we will rotate around.
+ const vec3 kRotationAxis = vec3(1, 2, 3).normalized();
+
+ // Some random angle we will be rotating by.
+ const real kRotationAngle = M_PI / 30;
+
+ // Random start orientation we are currently at.
+ const quat kStartOrientation = quat(5, 3, 4, 1).normalized();
+
+ // The orientation we will end up at.
+ const quat kEndOrientation =
+ kStartOrientation *
+ quat(Eigen::AngleAxis<real>(kRotationAngle, kRotationAxis));
+
+ // The delta time for going from start orientation to end.
+ const real kDeltaTime = 1.0;
+
+ // Compute the angular velocity from start orientation to end.
+ const auto angularVelocity = Predictor::AngularVelocity(
+ kStartOrientation, kEndOrientation, kDeltaTime);
+
+ // Extract the axis and the angular speed.
+ const auto angularSpeed = angularVelocity.norm();
+ const auto rotationAxis = angularVelocity.normalized();
+
+ // The speed must match.
+ EXPECT_NEAR(angularSpeed, kRotationAngle / kDeltaTime, kAbsErrorTolerance);
+
+ // The rotation axis must match.
+ EXPECT_NEAR(rotationAxis[0], kRotationAxis[0], kAbsErrorTolerance);
+ EXPECT_NEAR(rotationAxis[1], kRotationAxis[1], kAbsErrorTolerance);
+ EXPECT_NEAR(rotationAxis[2], kRotationAxis[2], kAbsErrorTolerance);
+}
+
+} // namespace
+
+} // namespace posepredictor
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 5309acf..bb70c5c 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -25,7 +25,13 @@
DisplayService::DisplayService(Hwc2::Composer* hidl)
: BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
- hardware_composer_(hidl) {}
+ hardware_composer_(hidl) {
+ hardware_composer_.Initialize();
+}
+
+bool DisplayService::IsInitialized() const {
+ return BASE::IsInitialized() && hardware_composer_.IsInitialized();
+}
std::string DisplayService::DumpState(size_t max_length) {
std::vector<char> buffer(max_length);
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 5de4f1d..b207e4d 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -23,6 +23,7 @@
// DisplayService implements the displayd display service over ServiceFS.
class DisplayService : public pdx::ServiceBase<DisplayService> {
public:
+ bool IsInitialized() const override;
std::string DumpState(size_t max_length) override;
void OnChannelClose(pdx::Message& message,
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index e6ed665..f801d9b 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -100,7 +100,8 @@
}
HardwareComposer::HardwareComposer(Hwc2::Composer* hwc2_hidl)
- : hwc2_hidl_(hwc2_hidl),
+ : initialized_(false),
+ hwc2_hidl_(hwc2_hidl),
display_transform_(HWC_TRANSFORM_NONE),
display_surfaces_updated_(false),
hardware_layers_need_update_(false),
@@ -126,6 +127,51 @@
Suspend();
}
+bool HardwareComposer::Initialize() {
+ if (initialized_) {
+ ALOGE("HardwareComposer::Initialize: already initialized.");
+ return false;
+ }
+
+ int32_t ret = HWC2_ERROR_NONE;
+
+ Hwc2::Config config;
+ ret = (int32_t)hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
+
+ if (ret != HWC2_ERROR_NONE) {
+ ALOGE("HardwareComposer: Failed to get current display config : %d",
+ config);
+ return false;
+ }
+
+ ret =
+ GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_);
+
+ if (ret != HWC2_ERROR_NONE) {
+ ALOGE(
+ "HardwareComposer: Failed to get display attributes for current "
+ "configuration : %d",
+ ret);
+ return false;
+ }
+
+ ALOGI(
+ "HardwareComposer: primary display attributes: width=%d height=%d "
+ "vsync_period_ns=%d DPI=%dx%d",
+ native_display_metrics_.width, native_display_metrics_.height,
+ native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
+ native_display_metrics_.dpi.y);
+
+ // Set the display metrics but never use rotation to avoid the long latency of
+ // rotation processing in hwc.
+ display_transform_ = HWC_TRANSFORM_NONE;
+ display_metrics_ = native_display_metrics_;
+
+ initialized_ = true;
+
+ return initialized_;
+}
+
bool HardwareComposer::Resume() {
std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
if (post_thread_state_ == PostThreadState::kRunning) {
@@ -136,62 +182,6 @@
int32_t ret = HWC2_ERROR_NONE;
- static const uint32_t attributes[] = {
- HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_VSYNC_PERIOD,
- HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_NO_ATTRIBUTE,
- };
-
- std::vector<Hwc2::Config> configs;
- ret = (int32_t)hwc2_hidl_->getDisplayConfigs(HWC_DISPLAY_PRIMARY, &configs);
-
- if (ret != HWC2_ERROR_NONE) {
- ALOGE("HardwareComposer: Failed to get display configs");
- return false;
- }
-
- uint32_t num_configs = configs.size();
-
- for (size_t i = 0; i < num_configs; i++) {
- ALOGI("HardwareComposer: cfg[%zd/%zd] = 0x%08x", i, num_configs,
- configs[i]);
-
- ret = GetDisplayMetrics(HWC_DISPLAY_PRIMARY, configs[i],
- &native_display_metrics_);
-
- if (ret != HWC2_ERROR_NONE) {
- ALOGE("HardwareComposer: Failed to get display attributes %d", ret);
- continue;
- } else {
- ret =
- (int32_t)hwc2_hidl_->setActiveConfig(HWC_DISPLAY_PRIMARY, configs[i]);
-
- if (ret != HWC2_ERROR_NONE) {
- ALOGE("HardwareComposer: Failed to set display configuration; ret=%d",
- ret);
- continue;
- }
-
- break;
- }
- }
-
- if (ret != HWC2_ERROR_NONE) {
- ALOGE("HardwareComposer: Could not set a valid display configuration.");
- return false;
- }
-
- // Set the display metrics but never use rotation to avoid the long latency of
- // rotation processing in hwc.
- display_transform_ = HWC_TRANSFORM_NONE;
- display_metrics_ = native_display_metrics_;
-
- ALOGI(
- "HardwareComposer: primary display attributes: width=%d height=%d "
- "vsync_period_ns=%d DPI=%dx%d",
- native_display_metrics_.width, native_display_metrics_.height,
- native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
- native_display_metrics_.dpi.y);
-
// Always turn off vsync when we start.
EnableVsync(false);
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index b6aa807..e2a8b90 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -189,6 +189,10 @@
HardwareComposer(Hwc2::Composer* hidl);
~HardwareComposer();
+ bool Initialize();
+
+ bool IsInitialized() const { return initialized_; }
+
bool Suspend();
bool Resume();
@@ -303,6 +307,8 @@
void HandlePendingScreenshots();
+ bool initialized_;
+
// Hardware composer HAL device.
std::unique_ptr<Hwc2::Composer> hwc2_hidl_;
sp<ComposerCallback> callbacks_;
diff --git a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
index de012a0..772b21a 100644
--- a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
+++ b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
@@ -61,7 +61,7 @@
"The command
- EGLClientBuffer eglGeteNativeClientBufferANDROID(
+ EGLClientBuffer eglGetNativeClientBufferANDROID(
AHardwareBuffer *buffer)
may be used to create an EGLClientBuffer from an AHardwareBuffer object.
@@ -73,7 +73,7 @@
Errors
- If eglGeteNativeClientBufferANDROID fails, NULL will be returned, no
+ If eglGetNativeClientBufferANDROID fails, NULL will be returned, no
memory will be allocated, and the following error will be generated:
* If the value of buffer is NULL, the error EGL_BAD_PARAMETER is
@@ -92,5 +92,8 @@
Revision History
+#2 (Craig Donner, February 17, 2017)
+ - Fix typographical errors.
+
#1 (Craig Donner, January 27, 2017)
- Initial draft.
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 18ec5e3..7062c57 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -246,6 +246,19 @@
*/
static int getNeededCount(GLint pname) {
int needed = 1;
+#ifdef GL_ES_VERSION_3_0
+ // GLES 3.x pnames
+ switch (pname) {
+ case GL_MAX_VIEWPORT_DIMS:
+ needed = 2;
+ break;
+
+ case GL_PROGRAM_BINARY_FORMATS:
+ glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &needed);
+ break;
+ }
+#endif
+
#ifdef GL_ES_VERSION_2_0
// GLES 2.x pnames
switch (pname) {
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index ec47c8a..24c68ec 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -189,10 +189,6 @@
LOCAL_INIT_RC := surfaceflinger.rc
-ifneq ($(ENABLE_CPUSETS),)
- LOCAL_CFLAGS += -DENABLE_CPUSETS
-endif
-
ifeq ($(TARGET_USES_HWC2),true)
LOCAL_CFLAGS += -DUSE_HWC2
endif
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 3e9ef24..c6e6dcb 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -131,7 +131,7 @@
if (mIsUsingVrComposer) {
mComposer = IComposer::getService("vr_hwcomposer");
} else {
- mComposer = IComposer::getService("hwcomposer");
+ mComposer = IComposer::getService(); // use default name
}
if (mComposer == nullptr) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e129a3a..4419dc1 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -24,7 +24,7 @@
#undef HWC2_USE_CPP11
#include <ui/HdrCapabilities.h>
-#include <ui/mat4.h>
+#include <math/mat4.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index a6171f5..d72139e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -34,33 +34,6 @@
using namespace std::chrono_literals;
-static bool operator==(const hwc_color_t& lhs, const hwc_color_t& rhs) {
- return lhs.r == rhs.r &&
- lhs.g == rhs.g &&
- lhs.b == rhs.b &&
- lhs.a == rhs.a;
-}
-
-static bool operator==(const hwc_rect_t& lhs, const hwc_rect_t& rhs) {
- return lhs.left == rhs.left &&
- lhs.top == rhs.top &&
- lhs.right == rhs.right &&
- lhs.bottom == rhs.bottom;
-}
-
-static bool operator==(const hwc_frect_t& lhs, const hwc_frect_t& rhs) {
- return lhs.left == rhs.left &&
- lhs.top == rhs.top &&
- lhs.right == rhs.right &&
- lhs.bottom == rhs.bottom;
-}
-
-template <typename T>
-static inline bool operator!=(const T& lhs, const T& rhs)
-{
- return !(lhs == rhs);
-}
-
static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
{
auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
@@ -80,19 +53,6 @@
namespace android {
-void HWC2On1Adapter::DisplayContentsDeleter::operator()(
- hwc_display_contents_1_t* contents)
-{
- if (contents != nullptr) {
- for (size_t l = 0; l < contents->numHwLayers; ++l) {
- auto& layer = contents->hwLayers[l];
- std::free(const_cast<hwc_rect_t*>(layer.visibleRegionScreen.rects));
- std::free(const_cast<hwc_rect_t*>(layer.surfaceDamage.rects));
- }
- }
- std::free(contents);
-}
-
class HWC2On1Adapter::Callbacks : public hwc_procs_t {
public:
explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
@@ -161,8 +121,7 @@
}
void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount,
- int32_t* outCapabilities)
-{
+ int32_t* outCapabilities) {
if (outCapabilities == nullptr) {
*outCount = mCapabilities.size();
return;
@@ -179,8 +138,7 @@
}
hwc2_function_pointer_t HWC2On1Adapter::doGetFunction(
- FunctionDescriptor descriptor)
-{
+ FunctionDescriptor descriptor) {
switch (descriptor) {
// Device functions
case FunctionDescriptor::CreateVirtualDisplay:
@@ -350,8 +308,7 @@
// Device functions
Error HWC2On1Adapter::createVirtualDisplay(uint32_t width,
- uint32_t height, hwc2_display_t* outDisplay)
-{
+ uint32_t height, hwc2_display_t* outDisplay) {
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
if (mHwc1VirtualDisplay) {
@@ -381,8 +338,7 @@
return Error::None;
}
-Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId)
-{
+Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId) {
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
@@ -396,8 +352,7 @@
return Error::None;
}
-void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer)
-{
+void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer) {
if (outBuffer != nullptr) {
auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
*outSize = static_cast<uint32_t>(copiedBytes);
@@ -450,8 +405,7 @@
*outSize = static_cast<uint32_t>(mDumpString.size());
}
-uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount()
-{
+uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount() {
return mHwc1SupportsVirtualDisplays ? 1 : 0;
}
@@ -465,8 +419,7 @@
}
Error HWC2On1Adapter::registerCallback(Callback descriptor,
- hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer)
-{
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
if (!isValid(descriptor)) {
return Error::BadParameter;
}
@@ -553,11 +506,8 @@
HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type)
: mId(sNextId++),
mDevice(device),
- mDirtyCount(0),
mStateMutex(),
- mZIsDirty(false),
mHwc1RequestedContents(nullptr),
- mHwc1ReceivedContents(nullptr),
mRetireFence(),
mChanges(),
mHwc1Id(-1),
@@ -572,10 +522,13 @@
mOutputBuffer(),
mHasColorTransform(false),
mLayers(),
- mHwc1LayerMap() {}
+ mHwc1LayerMap(),
+ mNumAvailableRects(0),
+ mNextAvailableRect(nullptr),
+ mGeometryChanged(false)
+ {}
-Error HWC2On1Adapter::Display::acceptChanges()
-{
+Error HWC2On1Adapter::Display::acceptChanges() {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!mChanges) {
@@ -594,25 +547,21 @@
mChanges->clearTypeChanges();
- mHwc1RequestedContents = std::move(mHwc1ReceivedContents);
-
return Error::None;
}
-Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId)
-{
+Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
*outLayerId = layer->getId();
ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
- mZIsDirty = true;
+ markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId)
-{
+Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
const auto mapLayer = mDevice.mLayers.find(layerId);
@@ -631,12 +580,11 @@
}
}
ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
- mZIsDirty = true;
+ markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig)
-{
+Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!mActiveConfig) {
@@ -651,8 +599,7 @@
}
Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId,
- Attribute attribute, int32_t* outValue)
-{
+ Attribute attribute, int32_t* outValue) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
@@ -667,8 +614,7 @@
}
Error HWC2On1Adapter::Display::getChangedCompositionTypes(
- uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes)
-{
+ uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!mChanges) {
@@ -701,8 +647,7 @@
}
Error HWC2On1Adapter::Display::getColorModes(uint32_t* outNumModes,
- int32_t* outModes)
-{
+ int32_t* outModes) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!outModes) {
@@ -717,8 +662,7 @@
}
Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs,
- hwc2_config_t* outConfigs)
-{
+ hwc2_config_t* outConfigs) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!outConfigs) {
@@ -737,8 +681,7 @@
return Error::None;
}
-Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport)
-{
+Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
@@ -751,15 +694,13 @@
Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
- float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/)
-{
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
// This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
*outNumTypes = 0;
return Error::None;
}
-Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName)
-{
+Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!outName) {
@@ -772,8 +713,7 @@
}
Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements,
- hwc2_layer_t* outLayers, int32_t* outFences)
-{
+ hwc2_layer_t* outLayers, int32_t* outFences) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
uint32_t numWritten = 0;
@@ -799,8 +739,7 @@
Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests,
uint32_t* outNumElements, hwc2_layer_t* outLayers,
- int32_t* outLayerRequests)
-{
+ int32_t* outLayerRequests) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!mChanges) {
@@ -829,16 +768,14 @@
return Error::None;
}
-Error HWC2On1Adapter::Display::getType(int32_t* outType)
-{
+Error HWC2On1Adapter::Display::getType(int32_t* outType) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
*outType = static_cast<int32_t>(mType);
return Error::None;
}
-Error HWC2On1Adapter::Display::present(int32_t* outRetireFence)
-{
+Error HWC2On1Adapter::Display::present(int32_t* outRetireFence) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (mChanges) {
@@ -857,8 +794,7 @@
return Error::None;
}
-Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId)
-{
+Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
auto config = getConfig(configId);
@@ -890,8 +826,7 @@
}
Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target,
- int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/)
-{
+ int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
@@ -901,8 +836,7 @@
return Error::None;
}
-Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode)
-{
+Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode) {
std::unique_lock<std::recursive_mutex> lock (mStateMutex);
ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode);
@@ -933,8 +867,7 @@
return Error::None;
}
-Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint)
-{
+Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
ALOGV("%" PRIu64 "] setColorTransform(%d)", mId,
@@ -944,8 +877,7 @@
}
Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer,
- int32_t releaseFence)
-{
+ int32_t releaseFence) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
@@ -954,30 +886,25 @@
return Error::None;
}
-static bool isValid(PowerMode mode)
-{
+static bool isValid(PowerMode mode) {
switch (mode) {
case PowerMode::Off: // Fall-through
case PowerMode::DozeSuspend: // Fall-through
case PowerMode::Doze: // Fall-through
case PowerMode::On: return true;
- default: return false;
}
}
-static int getHwc1PowerMode(PowerMode mode)
-{
+static int getHwc1PowerMode(PowerMode mode) {
switch (mode) {
case PowerMode::Off: return HWC_POWER_MODE_OFF;
case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
case PowerMode::On: return HWC_POWER_MODE_NORMAL;
- default: return HWC_POWER_MODE_OFF;
}
}
-Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode)
-{
+Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode) {
if (!isValid(mode)) {
return Error::BadParameter;
}
@@ -1007,12 +934,11 @@
switch (enable) {
case Vsync::Enable: // Fall-through
case Vsync::Disable: return true;
- default: return false;
+ case Vsync::Invalid: return false;
}
}
-Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable)
-{
+Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable) {
if (!isValid(enable)) {
return Error::BadParameter;
}
@@ -1032,8 +958,7 @@
}
Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes,
- uint32_t* outNumRequests)
-{
+ uint32_t* outNumRequests) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
ALOGV("[%" PRIu64 "] Entering validate", mId);
@@ -1042,6 +967,8 @@
if (!mDevice.prepareAllDisplays()) {
return Error::BadDisplay;
}
+ } else {
+ ALOGE("Validate was called more than once!");
}
*outNumTypes = mChanges->getNumTypes();
@@ -1055,10 +982,7 @@
return *outNumTypes > 0 ? Error::HasChanges : Error::None;
}
-// Display helpers
-
-Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z)
-{
+Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
const auto mapLayer = mDevice.mLayers.find(layerId);
@@ -1090,7 +1014,7 @@
layer->setZ(z);
mLayers.emplace(std::move(layer));
- mZIsDirty = true;
+ markGeometryChanged();
return Error::None;
}
@@ -1159,8 +1083,7 @@
static_assert(attributesMatch<HWC_DISPLAY_COLOR_TRANSFORM>(),
"Tables out of sync");
-void HWC2On1Adapter::Display::populateConfigs()
-{
+void HWC2On1Adapter::Display::populateConfigs() {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
ALOGV("[%" PRIu64 "] populateConfigs", mId);
@@ -1238,8 +1161,7 @@
populateColorModes();
}
-void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height)
-{
+void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
mConfigs.emplace_back(std::make_shared<Config>(*this));
@@ -1252,8 +1174,7 @@
mActiveConfig = config;
}
-bool HWC2On1Adapter::Display::prepare()
-{
+bool HWC2On1Adapter::Display::prepare() {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
// Only prepare display contents for displays HWC1 knows about
@@ -1270,86 +1191,45 @@
ALOGV("[%" PRIu64 "] Entering prepare", mId);
- auto currentCount = mHwc1RequestedContents ?
- mHwc1RequestedContents->numHwLayers : 0;
- auto requiredCount = mLayers.size() + 1;
- ALOGV("[%" PRIu64 "] Requires %zd layers, %zd allocated in %p", mId,
- requiredCount, currentCount, mHwc1RequestedContents.get());
-
- bool layerCountChanged = (currentCount != requiredCount);
- if (layerCountChanged) {
- reallocateHwc1Contents();
- }
-
- bool applyAllState = false;
- if (layerCountChanged || mZIsDirty) {
- assignHwc1LayerIds();
- mZIsDirty = false;
- applyAllState = true;
- }
+ allocateRequestedContents();
+ assignHwc1LayerIds();
mHwc1RequestedContents->retireFenceFd = -1;
mHwc1RequestedContents->flags = 0;
- if (isDirty() || applyAllState) {
+ if (mGeometryChanged) {
mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
}
+ mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
+ mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
+ // +1 is for framebuffer target layer.
+ mHwc1RequestedContents->numHwLayers = mLayers.size() + 1;
for (auto& layer : mLayers) {
auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
hwc1Layer.releaseFenceFd = -1;
hwc1Layer.acquireFenceFd = -1;
ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
- layer->applyState(hwc1Layer, applyAllState);
+ layer->applyState(hwc1Layer);
}
- mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
- mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
-
prepareFramebufferTarget();
+ resetGeometryMarker();
+
return true;
}
-static void cloneHWCRegion(hwc_region_t& region)
-{
- auto size = sizeof(hwc_rect_t) * region.numRects;
- auto newRects = static_cast<hwc_rect_t*>(std::malloc(size));
- std::copy_n(region.rects, region.numRects, newRects);
- region.rects = newRects;
-}
-
-HWC2On1Adapter::Display::HWC1Contents
- HWC2On1Adapter::Display::cloneRequestedContents() const
-{
+void HWC2On1Adapter::Display::generateChanges() {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
- size_t size = sizeof(hwc_display_contents_1_t) +
- sizeof(hwc_layer_1_t) * (mHwc1RequestedContents->numHwLayers);
- auto contents = static_cast<hwc_display_contents_1_t*>(std::malloc(size));
- std::memcpy(contents, mHwc1RequestedContents.get(), size);
- for (size_t layerId = 0; layerId < contents->numHwLayers; ++layerId) {
- auto& layer = contents->hwLayers[layerId];
- // Deep copy the regions to avoid double-frees
- cloneHWCRegion(layer.visibleRegionScreen);
- cloneHWCRegion(layer.surfaceDamage);
- }
- return HWC1Contents(contents);
-}
-
-void HWC2On1Adapter::Display::setReceivedContents(HWC1Contents contents)
-{
- std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
- mHwc1ReceivedContents = std::move(contents);
-
mChanges.reset(new Changes);
- size_t numLayers = mHwc1ReceivedContents->numHwLayers;
+ size_t numLayers = mHwc1RequestedContents->numHwLayers;
for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
- const auto& receivedLayer = mHwc1ReceivedContents->hwLayers[hwc1Id];
+ const auto& receivedLayer = mHwc1RequestedContents->hwLayers[hwc1Id];
if (mHwc1LayerMap.count(hwc1Id) == 0) {
ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
- "setReceivedContents: HWC1 layer %zd doesn't have a"
+ "generateChanges: HWC1 layer %zd doesn't have a"
" matching HWC2 layer, and isn't the framebuffer target",
hwc1Id);
continue;
@@ -1361,14 +1241,12 @@
}
}
-bool HWC2On1Adapter::Display::hasChanges() const
-{
+bool HWC2On1Adapter::Display::hasChanges() const {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
return mChanges != nullptr;
}
-Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents)
-{
+Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
if (!mChanges || (mChanges->getNumTypes() > 0)) {
@@ -1404,15 +1282,13 @@
return Error::None;
}
-void HWC2On1Adapter::Display::addRetireFence(int fenceFd)
-{
+void HWC2On1Adapter::Display::addRetireFence(int fenceFd) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
mRetireFence.add(fenceFd);
}
void HWC2On1Adapter::Display::addReleaseFences(
- const hwc_display_contents_1_t& hwcContents)
-{
+ const hwc_display_contents_1_t& hwcContents) {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
size_t numLayers = hwcContents.numHwLayers;
@@ -1439,14 +1315,12 @@
}
}
-bool HWC2On1Adapter::Display::hasColorTransform() const
-{
+bool HWC2On1Adapter::Display::hasColorTransform() const {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
return mHasColorTransform;
}
-static std::string hwc1CompositionString(int32_t type)
-{
+static std::string hwc1CompositionString(int32_t type) {
switch (type) {
case HWC_FRAMEBUFFER: return "Framebuffer";
case HWC_OVERLAY: return "Overlay";
@@ -1459,8 +1333,7 @@
}
}
-static std::string hwc1TransformString(int32_t transform)
-{
+static std::string hwc1TransformString(int32_t transform) {
switch (transform) {
case 0: return "None";
case HWC_TRANSFORM_FLIP_H: return "FlipH";
@@ -1475,8 +1348,7 @@
}
}
-static std::string hwc1BlendModeString(int32_t mode)
-{
+static std::string hwc1BlendModeString(int32_t mode) {
switch (mode) {
case HWC_BLENDING_NONE: return "None";
case HWC_BLENDING_PREMULT: return "Premultiplied";
@@ -1486,16 +1358,14 @@
}
}
-static std::string rectString(hwc_rect_t rect)
-{
+static std::string rectString(hwc_rect_t rect) {
std::stringstream output;
output << "[" << rect.left << ", " << rect.top << ", ";
output << rect.right << ", " << rect.bottom << "]";
return output.str();
}
-static std::string approximateFloatString(float f)
-{
+static std::string approximateFloatString(float f) {
if (static_cast<int32_t>(f) == f) {
return std::to_string(static_cast<int32_t>(f));
}
@@ -1508,8 +1378,7 @@
return std::string(buffer, bytesWritten);
}
-static std::string frectString(hwc_frect_t frect)
-{
+static std::string frectString(hwc_frect_t frect) {
std::stringstream output;
output << "[" << approximateFloatString(frect.left) << ", ";
output << approximateFloatString(frect.top) << ", ";
@@ -1518,8 +1387,7 @@
return output.str();
}
-static std::string colorString(hwc_color_t color)
-{
+static std::string colorString(hwc_color_t color) {
std::stringstream output;
output << "RGBA [";
output << static_cast<int32_t>(color.r) << ", ";
@@ -1529,8 +1397,7 @@
return output.str();
}
-static std::string alphaString(float f)
-{
+static std::string alphaString(float f) {
const size_t BUFFER_SIZE = 8;
char buffer[BUFFER_SIZE] = {};
auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
@@ -1538,8 +1405,7 @@
}
static std::string to_string(const hwc_layer_1_t& hwcLayer,
- int32_t hwc1MinorVersion)
-{
+ int32_t hwc1MinorVersion) {
const char* fill = " ";
std::stringstream output;
@@ -1599,8 +1465,7 @@
}
static std::string to_string(const hwc_display_contents_1_t& hwcContents,
- int32_t hwc1MinorVersion)
-{
+ int32_t hwc1MinorVersion) {
const char* fill = " ";
std::stringstream output;
@@ -1622,8 +1487,7 @@
return output.str();
}
-std::string HWC2On1Adapter::Display::dump() const
-{
+std::string HWC2On1Adapter::Display::dump() const {
std::unique_lock<std::recursive_mutex> lock(mStateMutex);
std::stringstream output;
@@ -1663,10 +1527,7 @@
output << " Output buffer: " << mOutputBuffer.getBuffer() << '\n';
}
- if (mHwc1ReceivedContents) {
- output << " Last received HWC1 state\n";
- output << to_string(*mHwc1ReceivedContents, mDevice.mHwc1MinorVersion);
- } else if (mHwc1RequestedContents) {
+ if (mHwc1RequestedContents) {
output << " Last requested HWC1 state\n";
output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
}
@@ -1674,28 +1535,46 @@
return output.str();
}
+hwc_rect_t* HWC2On1Adapter::Display::GetRects(size_t numRects) {
+ if (numRects == 0) {
+ return nullptr;
+ }
+
+ if (numRects > mNumAvailableRects) {
+ // This should NEVER happen since we calculated how many rects the
+ // display would need.
+ ALOGE("Rect allocation failure! SF is likely to crash soon!");
+ return nullptr;
+
+ }
+ hwc_rect_t* rects = mNextAvailableRect;
+ mNextAvailableRect += numRects;
+ mNumAvailableRects -= numRects;
+ return rects;
+}
+
+hwc_display_contents_1* HWC2On1Adapter::Display::getDisplayContents() {
+ return mHwc1RequestedContents.get();
+}
+
void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute,
- int32_t value)
-{
+ int32_t value) {
mAttributes[attribute] = value;
}
-int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const
-{
+int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const {
if (mAttributes.count(attribute) == 0) {
return -1;
}
return mAttributes.at(attribute);
}
-void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id)
-{
+void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id) {
android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
mHwc1Ids.emplace(colorMode, id);
}
-bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const
-{
+bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const {
for (const auto& idPair : mHwc1Ids) {
if (id == idPair.second) {
return true;
@@ -1705,8 +1584,7 @@
}
Error HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
- uint32_t id, android_color_mode_t* outMode) const
-{
+ uint32_t id, android_color_mode_t* outMode) const {
for (const auto& idPair : mHwc1Ids) {
if (id == idPair.second) {
*outMode = idPair.first;
@@ -1718,8 +1596,7 @@
}
Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
- uint32_t* outId) const
-{
+ uint32_t* outId) const {
for (const auto& idPair : mHwc1Ids) {
if (mode == idPair.first) {
*outId = idPair.second;
@@ -1730,8 +1607,7 @@
return Error::BadParameter;
}
-bool HWC2On1Adapter::Display::Config::merge(const Config& other)
-{
+bool HWC2On1Adapter::Display::Config::merge(const Config& other) {
auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height,
HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX,
HWC2::Attribute::DpiY};
@@ -1753,8 +1629,7 @@
return true;
}
-std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const
-{
+std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const {
std::set<android_color_mode_t> colorModes;
for (const auto& idPair : mHwc1Ids) {
colorModes.emplace(idPair.first);
@@ -1762,8 +1637,7 @@
return colorModes;
}
-std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const
-{
+std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const {
std::string output;
const size_t BUFFER_SIZE = 100;
@@ -1819,16 +1693,14 @@
}
std::shared_ptr<const HWC2On1Adapter::Display::Config>
- HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const
-{
+ HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const {
if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
return nullptr;
}
return mConfigs[configId];
}
-void HWC2On1Adapter::Display::populateColorModes()
-{
+void HWC2On1Adapter::Display::populateColorModes() {
mColorModes = mConfigs[0]->getColorModes();
for (const auto& config : mConfigs) {
std::set<android_color_mode_t> intersection;
@@ -1840,8 +1712,7 @@
}
}
-void HWC2On1Adapter::Display::initializeActiveConfig()
-{
+void HWC2On1Adapter::Display::initializeActiveConfig() {
if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
ALOGV("getActiveConfig is null, choosing config 0");
mActiveConfig = mConfigs[0];
@@ -1886,22 +1757,40 @@
}
-void HWC2On1Adapter::Display::reallocateHwc1Contents()
-{
- // Allocate an additional layer for the framebuffer target
+void HWC2On1Adapter::Display::allocateRequestedContents() {
+ // What needs to be allocated:
+ // 1 hwc_display_contents_1_t
+ // 1 hwc_layer_1_t for each layer
+ // 1 hwc_rect_t for each layer's surfaceDamage
+ // 1 hwc_rect_t for each layer's visibleRegion
+ // 1 hwc_layer_1_t for the framebuffer
+ // 1 hwc_rect_t for the framebuffer's visibleRegion
+
+ // Count # of surfaceDamage
+ size_t numSurfaceDamages = 0;
+ for (const auto& layer : mLayers) {
+ numSurfaceDamages += layer->getNumSurfaceDamages();
+ }
+
+ // Count # of visibleRegions (start at 1 for mandatory framebuffer target
+ // region)
+ size_t numVisibleRegion = 1;
+ for (const auto& layer : mLayers) {
+ numVisibleRegion += layer->getNumVisibleRegions();
+ }
+
+ size_t numRects = numVisibleRegion + numSurfaceDamages;
auto numLayers = mLayers.size() + 1;
size_t size = sizeof(hwc_display_contents_1_t) +
- sizeof(hwc_layer_1_t) * numLayers;
- ALOGV("[%" PRIu64 "] reallocateHwc1Contents creating %zd layer%s", mId,
- numLayers, numLayers != 1 ? "s" : "");
- auto contents =
- static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
- contents->numHwLayers = numLayers;
+ sizeof(hwc_layer_1_t) * numLayers +
+ sizeof(hwc_rect_t) * numRects;
+ auto contents = static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
mHwc1RequestedContents.reset(contents);
+ mNextAvailableRect = reinterpret_cast<hwc_rect_t*>(&contents->hwLayers[numLayers]);
+ mNumAvailableRects = numRects;
}
-void HWC2On1Adapter::Display::assignHwc1LayerIds()
-{
+void HWC2On1Adapter::Display::assignHwc1LayerIds() {
mHwc1LayerMap.clear();
size_t nextHwc1Id = 0;
for (auto& layer : mLayers) {
@@ -1911,8 +1800,7 @@
}
void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
- const Layer& layer)
-{
+ const Layer& layer) {
auto layerId = layer.getId();
switch (hwc1Layer.compositionType) {
case HWC_FRAMEBUFFER:
@@ -1947,16 +1835,14 @@
}
void HWC2On1Adapter::Display::updateLayerRequests(
- const hwc_layer_1_t& hwc1Layer, const Layer& layer)
-{
+ const hwc_layer_1_t& hwc1Layer, const Layer& layer) {
if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
mChanges->addLayerRequest(layer.getId(),
LayerRequest::ClearClientTarget);
}
}
-void HWC2On1Adapter::Display::prepareFramebufferTarget()
-{
+void HWC2On1Adapter::Display::prepareFramebufferTarget() {
// We check that mActiveConfig is valid in Display::prepare
int32_t width = mActiveConfig->getAttribute(Attribute::Width);
int32_t height = mActiveConfig->getAttribute(Attribute::Height);
@@ -1976,8 +1862,9 @@
}
hwc1Target.displayFrame = {0, 0, width, height};
hwc1Target.planeAlpha = 255;
+
hwc1Target.visibleRegionScreen.numRects = 1;
- auto rects = static_cast<hwc_rect_t*>(std::malloc(sizeof(hwc_rect_t)));
+ hwc_rect_t* rects = GetRects(1);
rects[0].left = 0;
rects[0].top = 0;
rects[0].right = width;
@@ -1995,42 +1882,37 @@
HWC2On1Adapter::Layer::Layer(Display& display)
: mId(sNextId++),
mDisplay(display),
- mDirtyCount(0),
mBuffer(),
mSurfaceDamage(),
- mBlendMode(*this, BlendMode::None),
- mColor(*this, {0, 0, 0, 0}),
- mCompositionType(*this, Composition::Invalid),
- mDisplayFrame(*this, {0, 0, -1, -1}),
- mPlaneAlpha(*this, 0.0f),
- mSidebandStream(*this, nullptr),
- mSourceCrop(*this, {0.0f, 0.0f, -1.0f, -1.0f}),
- mTransform(*this, Transform::None),
- mVisibleRegion(*this, std::vector<hwc_rect_t>()),
+ mBlendMode(BlendMode::None),
+ mColor({0, 0, 0, 0}),
+ mCompositionType(Composition::Invalid),
+ mDisplayFrame({0, 0, -1, -1}),
+ mPlaneAlpha(0.0f),
+ mSidebandStream(nullptr),
+ mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
+ mTransform(Transform::None),
+ mVisibleRegion(),
mZ(0),
mReleaseFence(),
mHwc1Id(0),
- mHasUnsupportedPlaneAlpha(false),
- mHasUnsupportedBackgroundColor(false) {}
+ mHasUnsupportedPlaneAlpha(false) {}
bool HWC2On1Adapter::SortLayersByZ::operator()(
- const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs)
-{
+ const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs) {
return lhs->getZ() < rhs->getZ();
}
Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer,
- int32_t acquireFence)
-{
+ int32_t acquireFence) {
ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
mBuffer.setBuffer(buffer);
mBuffer.setFence(acquireFence);
return Error::None;
}
-Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y)
-{
- if (mCompositionType.getValue() != Composition::Cursor) {
+Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y) {
+ if (mCompositionType != Composition::Cursor) {
return Error::BadLayer;
}
@@ -2044,8 +1926,11 @@
return Error::None;
}
-Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage)
-{
+Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage) {
+ // HWC1 supports surface damage starting only with version 1.5.
+ if (mDisplay.getDevice().mHwc1MinorVersion < 5) {
+ return Error::None;
+ }
mSurfaceDamage.resize(damage.numRects);
std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
return Error::None;
@@ -2053,104 +1938,91 @@
// Layer state functions
-Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode)
-{
- mBlendMode.setPending(mode);
+Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode) {
+ mBlendMode = mode;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setColor(hwc_color_t color)
-{
- mColor.setPending(color);
+Error HWC2On1Adapter::Layer::setColor(hwc_color_t color) {
+ mColor = color;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setCompositionType(Composition type)
-{
- mCompositionType.setPending(type);
+Error HWC2On1Adapter::Layer::setCompositionType(Composition type) {
+ mCompositionType = type;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t)
-{
+Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t) {
return Error::None;
}
-Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame)
-{
- mDisplayFrame.setPending(frame);
+Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame) {
+ mDisplayFrame = frame;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha)
-{
- mPlaneAlpha.setPending(alpha);
+Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha) {
+ mPlaneAlpha = alpha;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream)
-{
- mSidebandStream.setPending(stream);
+Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream) {
+ mSidebandStream = stream;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop)
-{
- mSourceCrop.setPending(crop);
+Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop) {
+ mSourceCrop = crop;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setTransform(Transform transform)
-{
- mTransform.setPending(transform);
+Error HWC2On1Adapter::Layer::setTransform(Transform transform) {
+ mTransform = transform;
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t rawVisible)
-{
- std::vector<hwc_rect_t> visible(rawVisible.rects,
- rawVisible.rects + rawVisible.numRects);
- mVisibleRegion.setPending(std::move(visible));
+Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ mDisplay.markGeometryChanged();
return Error::None;
}
-Error HWC2On1Adapter::Layer::setZ(uint32_t z)
-{
+Error HWC2On1Adapter::Layer::setZ(uint32_t z) {
mZ = z;
return Error::None;
}
-void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd)
-{
+void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd) {
ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
mReleaseFence.add(fenceFd);
}
-const sp<Fence>& HWC2On1Adapter::Layer::getReleaseFence() const
-{
+const sp<Fence>& HWC2On1Adapter::Layer::getReleaseFence() const {
return mReleaseFence.get();
}
-void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer,
- bool applyAllState)
-{
- applyCommonState(hwc1Layer, applyAllState);
- auto compositionType = mCompositionType.getPendingValue();
- if (compositionType == Composition::SolidColor) {
- applySolidColorState(hwc1Layer, applyAllState);
- } else if (compositionType == Composition::Sideband) {
- applySidebandState(hwc1Layer, applyAllState);
- } else {
- applyBufferState(hwc1Layer);
+void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer) {
+ applyCommonState(hwc1Layer);
+ applyCompositionType(hwc1Layer);
+ switch (mCompositionType) {
+ case Composition::SolidColor : applySolidColorState(hwc1Layer); break;
+ case Composition::Sideband : applySidebandState(hwc1Layer); break;
+ default: applyBufferState(hwc1Layer); break;
}
- applyCompositionType(hwc1Layer, applyAllState);
}
-// Layer dump helpers
-
static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
- const std::vector<hwc_rect_t>& surfaceDamage)
-{
+ const std::vector<hwc_rect_t>& surfaceDamage) {
std::string regions;
regions += " Visible Region";
regions.resize(40, ' ');
@@ -2178,40 +2050,38 @@
return regions;
}
-std::string HWC2On1Adapter::Layer::dump() const
-{
+std::string HWC2On1Adapter::Layer::dump() const {
std::stringstream output;
const char* fill = " ";
- output << fill << to_string(mCompositionType.getPendingValue());
+ output << fill << to_string(mCompositionType);
output << " Layer HWC2/1: " << mId << "/" << mHwc1Id << " ";
output << "Z: " << mZ;
- if (mCompositionType.getValue() == HWC2::Composition::SolidColor) {
- output << " " << colorString(mColor.getValue());
- } else if (mCompositionType.getValue() == HWC2::Composition::Sideband) {
- output << " Handle: " << mSidebandStream.getValue() << '\n';
+ if (mCompositionType == HWC2::Composition::SolidColor) {
+ output << " " << colorString(mColor);
+ } else if (mCompositionType == HWC2::Composition::Sideband) {
+ output << " Handle: " << mSidebandStream << '\n';
} else {
output << " Buffer: " << mBuffer.getBuffer() << "/" <<
mBuffer.getFence() << '\n';
output << fill << " Display frame [LTRB]: " <<
- rectString(mDisplayFrame.getValue()) << '\n';
+ rectString(mDisplayFrame) << '\n';
output << fill << " Source crop: " <<
- frectString(mSourceCrop.getValue()) << '\n';
- output << fill << " Transform: " << to_string(mTransform.getValue());
- output << " Blend mode: " << to_string(mBlendMode.getValue());
- if (mPlaneAlpha.getValue() != 1.0f) {
+ frectString(mSourceCrop) << '\n';
+ output << fill << " Transform: " << to_string(mTransform);
+ output << " Blend mode: " << to_string(mBlendMode);
+ if (mPlaneAlpha != 1.0f) {
output << " Alpha: " <<
- alphaString(mPlaneAlpha.getValue()) << '\n';
+ alphaString(mPlaneAlpha) << '\n';
} else {
output << '\n';
}
- output << regionStrings(mVisibleRegion.getValue(), mSurfaceDamage);
+ output << regionStrings(mVisibleRegion, mSurfaceDamage);
}
return output.str();
}
-static int getHwc1Blending(HWC2::BlendMode blendMode)
-{
+static int getHwc1Blending(HWC2::BlendMode blendMode) {
switch (blendMode) {
case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
@@ -2219,168 +2089,124 @@
}
}
-void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer,
- bool applyAllState)
-{
+void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer) {
auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
- if (applyAllState || mBlendMode.isDirty()) {
- hwc1Layer.blending = getHwc1Blending(mBlendMode.getPendingValue());
- mBlendMode.latch();
- }
- if (applyAllState || mDisplayFrame.isDirty()) {
- hwc1Layer.displayFrame = mDisplayFrame.getPendingValue();
- mDisplayFrame.latch();
- }
- if (applyAllState || mPlaneAlpha.isDirty()) {
- auto pendingAlpha = mPlaneAlpha.getPendingValue();
- if (minorVersion < 2) {
- mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
- } else {
- hwc1Layer.planeAlpha =
- static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
- }
- mPlaneAlpha.latch();
- }
- if (applyAllState || mSourceCrop.isDirty()) {
- if (minorVersion < 3) {
- auto pending = mSourceCrop.getPendingValue();
- hwc1Layer.sourceCropi.left =
- static_cast<int32_t>(std::ceil(pending.left));
- hwc1Layer.sourceCropi.top =
- static_cast<int32_t>(std::ceil(pending.top));
- hwc1Layer.sourceCropi.right =
- static_cast<int32_t>(std::floor(pending.right));
- hwc1Layer.sourceCropi.bottom =
- static_cast<int32_t>(std::floor(pending.bottom));
- } else {
- hwc1Layer.sourceCropf = mSourceCrop.getPendingValue();
- }
- mSourceCrop.latch();
- }
- if (applyAllState || mTransform.isDirty()) {
- hwc1Layer.transform =
- static_cast<uint32_t>(mTransform.getPendingValue());
- mTransform.latch();
- }
- if (applyAllState || mVisibleRegion.isDirty()) {
- auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
+ hwc1Layer.blending = getHwc1Blending(mBlendMode);
+ hwc1Layer.displayFrame = mDisplayFrame;
- std::free(const_cast<hwc_rect_t*>(hwc1VisibleRegion.rects));
+ auto pendingAlpha = mPlaneAlpha;
+ if (minorVersion < 2) {
+ mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
+ } else {
+ hwc1Layer.planeAlpha =
+ static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
+ }
- auto pending = mVisibleRegion.getPendingValue();
- hwc_rect_t* newRects = static_cast<hwc_rect_t*>(
- std::malloc(sizeof(hwc_rect_t) * pending.size()));
- std::copy(pending.begin(), pending.end(), newRects);
- hwc1VisibleRegion.rects = const_cast<const hwc_rect_t*>(newRects);
- hwc1VisibleRegion.numRects = pending.size();
- mVisibleRegion.latch();
+ if (minorVersion < 3) {
+ auto pending = mSourceCrop;
+ hwc1Layer.sourceCropi.left =
+ static_cast<int32_t>(std::ceil(pending.left));
+ hwc1Layer.sourceCropi.top =
+ static_cast<int32_t>(std::ceil(pending.top));
+ hwc1Layer.sourceCropi.right =
+ static_cast<int32_t>(std::floor(pending.right));
+ hwc1Layer.sourceCropi.bottom =
+ static_cast<int32_t>(std::floor(pending.bottom));
+ } else {
+ hwc1Layer.sourceCropf = mSourceCrop;
+ }
+
+ hwc1Layer.transform = static_cast<uint32_t>(mTransform);
+
+ auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
+ hwc1VisibleRegion.numRects = mVisibleRegion.size();
+ hwc_rect_t* rects = mDisplay.GetRects(hwc1VisibleRegion.numRects);
+ hwc1VisibleRegion.rects = rects;
+ for (size_t i = 0; i < mVisibleRegion.size(); i++) {
+ rects[i] = mVisibleRegion[i];
}
}
-void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer,
- bool applyAllState)
-{
- if (applyAllState || mColor.isDirty()) {
- // If the device does not support background color it is likely to make
- // assumption regarding backgroundColor and handle (both fields occupy
- // the same location in hwc_layer_1_t union).
- // To not confuse these devices we don't set background color and we
- // make sure handle is a null pointer.
- if (mDisplay.getDevice().supportsBackgroundColor()) {
- hwc1Layer.backgroundColor = mColor.getPendingValue();
- mHasUnsupportedBackgroundColor = false;
- } else {
- hwc1Layer.handle = nullptr;
- mHasUnsupportedBackgroundColor = true;
- }
- mColor.latch();
+void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer) {
+ // If the device does not support background color it is likely to make
+ // assumption regarding backgroundColor and handle (both fields occupy
+ // the same location in hwc_layer_1_t union).
+ // To not confuse these devices we don't set background color and we
+ // make sure handle is a null pointer.
+ if (hasUnsupportedBackgroundColor()) {
+ hwc1Layer.handle = nullptr;
+ } else {
+ hwc1Layer.backgroundColor = mColor;
}
}
-void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer,
- bool applyAllState)
-{
- if (applyAllState || mSidebandStream.isDirty()) {
- hwc1Layer.sidebandStream = mSidebandStream.getPendingValue();
- mSidebandStream.latch();
- }
+void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer) {
+ hwc1Layer.sidebandStream = mSidebandStream;
}
-void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer)
-{
+void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) {
hwc1Layer.handle = mBuffer.getBuffer();
hwc1Layer.acquireFenceFd = mBuffer.getFence();
}
-void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer,
- bool applyAllState)
-{
+void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer) {
// HWC1 never supports color transforms or dataspaces and only sometimes
// supports plane alpha (depending on the version). These require us to drop
// some or all layers to client composition.
- ALOGV("applyCompositionType");
- ALOGV("mHasUnsupportedPlaneAlpha = %d", mHasUnsupportedPlaneAlpha);
- ALOGV("mDisplay.hasColorTransform() = %d", mDisplay.hasColorTransform());
- ALOGV("mHasUnsupportedBackgroundColor = %d", mHasUnsupportedBackgroundColor);
-
if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
- mHasUnsupportedBackgroundColor) {
+ hasUnsupportedBackgroundColor()) {
hwc1Layer.compositionType = HWC_FRAMEBUFFER;
hwc1Layer.flags = HWC_SKIP_LAYER;
return;
}
- if (applyAllState || mCompositionType.isDirty()) {
- hwc1Layer.flags = 0;
- switch (mCompositionType.getPendingValue()) {
- case Composition::Client:
+ hwc1Layer.flags = 0;
+ switch (mCompositionType) {
+ case Composition::Client:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Device:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ break;
+ case Composition::SolidColor:
+ // In theory the following line should work, but since the HWC1
+ // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
+ // devices may not work correctly. To be on the safe side, we
+ // fall back to client composition.
+ //
+ // hwc1Layer.compositionType = HWC_BACKGROUND;
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Cursor:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
+ hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
+ }
+ break;
+ case Composition::Sideband:
+ if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
+ hwc1Layer.compositionType = HWC_SIDEBAND;
+ } else {
hwc1Layer.compositionType = HWC_FRAMEBUFFER;
hwc1Layer.flags |= HWC_SKIP_LAYER;
- break;
- case Composition::Device:
- hwc1Layer.compositionType = HWC_FRAMEBUFFER;
- break;
- case Composition::SolidColor:
- // In theory the following line should work, but since the HWC1
- // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
- // devices may not work correctly. To be on the safe side, we
- // fall back to client composition.
- //
- // hwc1Layer.compositionType = HWC_BACKGROUND;
- hwc1Layer.compositionType = HWC_FRAMEBUFFER;
- hwc1Layer.flags |= HWC_SKIP_LAYER;
- break;
- case Composition::Cursor:
- hwc1Layer.compositionType = HWC_FRAMEBUFFER;
- if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
- hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
- }
- break;
- case Composition::Sideband:
- if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
- hwc1Layer.compositionType = HWC_SIDEBAND;
- } else {
- hwc1Layer.compositionType = HWC_FRAMEBUFFER;
- hwc1Layer.flags |= HWC_SKIP_LAYER;
- }
- break;
- default:
- hwc1Layer.compositionType = HWC_FRAMEBUFFER;
- hwc1Layer.flags |= HWC_SKIP_LAYER;
- break;
- }
- ALOGV("Layer %" PRIu64 " %s set to %d", mId,
- to_string(mCompositionType.getPendingValue()).c_str(),
- hwc1Layer.compositionType);
- ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, " and skipping");
- mCompositionType.latch();
+ }
+ break;
+ default:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
}
+ ALOGV("Layer %" PRIu64 " %s set to %d", mId,
+ to_string(mCompositionType).c_str(),
+ hwc1Layer.compositionType);
+ ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, " and skipping");
}
// Adapter helpers
-void HWC2On1Adapter::populateCapabilities()
-{
+void HWC2On1Adapter::populateCapabilities() {
ALOGV("populateCapabilities");
if (mHwc1MinorVersion >= 3U) {
int supportedTypes = 0;
@@ -2408,8 +2234,7 @@
}
}
-HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id)
-{
+HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
auto display = mDisplays.find(id);
@@ -2421,8 +2246,7 @@
}
std::tuple<HWC2On1Adapter::Layer*, Error> HWC2On1Adapter::getLayer(
- hwc2_display_t displayId, hwc2_layer_t layerId)
-{
+ hwc2_display_t displayId, hwc2_layer_t layerId) {
auto display = getDisplay(displayId);
if (!display) {
return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
@@ -2440,22 +2264,19 @@
return std::make_tuple(layer.get(), Error::None);
}
-void HWC2On1Adapter::populatePrimary()
-{
+void HWC2On1Adapter::populatePrimary() {
ALOGV("populatePrimary");
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
- auto display =
- std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+ auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
display->setHwc1Id(HWC_DISPLAY_PRIMARY);
display->populateConfigs();
mDisplays.emplace(display->getId(), std::move(display));
}
-bool HWC2On1Adapter::prepareAllDisplays()
-{
+bool HWC2On1Adapter::prepareAllDisplays() {
ATRACE_CALL();
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
@@ -2472,24 +2293,23 @@
return false;
}
+ // Build an array of hwc_display_contents_1 to call prepare() on HWC1.
+ mHwc1Contents.clear();
+
// Always push the primary display
- std::vector<HWC2On1Adapter::Display::HWC1Contents> requestedContents;
auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
auto& primaryDisplay = mDisplays[primaryDisplayId];
- auto primaryDisplayContents = primaryDisplay->cloneRequestedContents();
- requestedContents.push_back(std::move(primaryDisplayContents));
+ mHwc1Contents.push_back(primaryDisplay->getDisplayContents());
// Push the external display, if present
if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
auto& externalDisplay = mDisplays[externalDisplayId];
- auto externalDisplayContents =
- externalDisplay->cloneRequestedContents();
- requestedContents.push_back(std::move(externalDisplayContents));
+ mHwc1Contents.push_back(externalDisplay->getDisplayContents());
} else {
// Even if an external display isn't present, we still need to send
// at least two displays down to HWC1
- requestedContents.push_back(nullptr);
+ mHwc1Contents.push_back(nullptr);
}
// Push the hardware virtual display, if supported and present
@@ -2497,17 +2317,13 @@
if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
auto& virtualDisplay = mDisplays[virtualDisplayId];
- auto virtualDisplayContents =
- virtualDisplay->cloneRequestedContents();
- requestedContents.push_back(std::move(virtualDisplayContents));
+ mHwc1Contents.push_back(virtualDisplay->getDisplayContents());
} else {
- requestedContents.push_back(nullptr);
+ mHwc1Contents.push_back(nullptr);
}
}
- mHwc1Contents.clear();
- for (auto& displayContents : requestedContents) {
- mHwc1Contents.push_back(displayContents.get());
+ for (auto& displayContents : mHwc1Contents) {
if (!displayContents) {
continue;
}
@@ -2545,14 +2361,13 @@
auto displayId = mHwc1DisplayMap[hwc1Id];
auto& display = mDisplays[displayId];
- display->setReceivedContents(std::move(requestedContents[hwc1Id]));
+ display->generateChanges();
}
return true;
}
-Error HWC2On1Adapter::setAllDisplays()
-{
+Error HWC2On1Adapter::setAllDisplays() {
ATRACE_CALL();
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
@@ -2598,14 +2413,13 @@
return Error::None;
}
-void HWC2On1Adapter::hwc1Invalidate()
-{
+void HWC2On1Adapter::hwc1Invalidate() {
ALOGV("Received hwc1Invalidate");
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
// If the HWC2-side callback hasn't been registered yet, buffer this until
- // it is registered
+ // it is registered.
if (mCallbacks.count(Callback::Refresh) == 0) {
mHasPendingInvalidate = true;
return;
@@ -2617,7 +2431,7 @@
displays.emplace_back(displayPair.first);
}
- // Call back without the state lock held
+ // Call back without the state lock held.
lock.unlock();
auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
@@ -2626,14 +2440,13 @@
}
}
-void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp)
-{
+void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) {
ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
// If the HWC2-side callback hasn't been registered yet, buffer this until
- // it is registered
+ // it is registered.
if (mCallbacks.count(Callback::Vsync) == 0) {
mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
return;
@@ -2647,15 +2460,14 @@
const auto& callbackInfo = mCallbacks[Callback::Vsync];
auto displayId = mHwc1DisplayMap[hwc1DisplayId];
- // Call back without the state lock held
+ // Call back without the state lock held.
lock.unlock();
auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
vsync(callbackInfo.data, displayId, timestamp);
}
-void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected)
-{
+void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
@@ -2710,5 +2522,4 @@
HWC2::Connection::Disconnected : HWC2::Connection::Connected;
hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
}
-
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index df33ec3..408bc41 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -134,11 +134,6 @@
const std::shared_ptr<Layer>& rhs);
};
- class DisplayContentsDeleter {
- public:
- void operator()(struct hwc_display_contents_1* contents);
- };
-
// The semantics of the fences returned by the device differ between
// hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
// for more information.
@@ -193,9 +188,6 @@
class Display {
public:
- typedef std::unique_ptr<hwc_display_contents_1,
- DisplayContentsDeleter> HWC1Contents;
-
Display(HWC2On1Adapter& device, HWC2::DisplayType type);
hwc2_display_t getId() const { return mId; }
@@ -206,10 +198,6 @@
void setHwc1Id(int32_t id) { mHwc1Id = id; }
int32_t getHwc1Id() const { return mHwc1Id; }
- void incDirty() { ++mDirtyCount; }
- void decDirty() { --mDirtyCount; }
- bool isDirty() const { return mDirtyCount > 0 || mZIsDirty; }
-
// HWC2 Display functions
HWC2::Error acceptChanges();
HWC2::Error createLayer(hwc2_layer_t* outLayerId);
@@ -233,7 +221,14 @@
uint32_t* outNumElements, hwc2_layer_t* outLayers,
int32_t* outLayerRequests);
HWC2::Error getType(int32_t* outType);
+
+ // Since HWC1 "presents" (called "set" in HWC1) all Displays
+ // at once, the first call to any Display::present will trigger
+ // present() on all Displays in the Device. Subsequent calls without
+ // first calling validate() are noop (except for duping/returning
+ // the retire fence).
HWC2::Error present(int32_t* outRetireFence);
+
HWC2::Error setActiveConfig(hwc2_config_t configId);
HWC2::Error setClientTarget(buffer_handle_t target,
int32_t acquireFence, int32_t dataspace,
@@ -244,6 +239,10 @@
int32_t releaseFence);
HWC2::Error setPowerMode(HWC2::PowerMode mode);
HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
+
+ // Since HWC1 "validates" (called "prepare" in HWC1) all Displays
+ // at once, the first call to any Display::validate() will trigger
+ // validate() on all other Displays in the Device.
HWC2::Error validate(uint32_t* outNumTypes,
uint32_t* outNumRequests);
@@ -256,10 +255,9 @@
void populateConfigs(uint32_t width, uint32_t height);
bool prepare();
- HWC1Contents cloneRequestedContents() const;
// Called after hwc.prepare() with responses from the device.
- void setReceivedContents(HWC1Contents contents);
+ void generateChanges();
bool hasChanges() const;
HWC2::Error set(hwc_display_contents_1& hwcContents);
@@ -270,6 +268,13 @@
std::string dump() const;
+ // Return a rect from the pool allocated during validate()
+ hwc_rect_t* GetRects(size_t numRects);
+
+ hwc_display_contents_1* getDisplayContents();
+
+ void markGeometryChanged() { mGeometryChanged = true; }
+ void resetGeometryMarker() { mGeometryChanged = false;}
private:
class Config {
public:
@@ -314,7 +319,7 @@
std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
};
- // Store changes requested from the device upon calling prepare().
+ // Stores changes requested from the device upon calling prepare().
// Handles change request to:
// - Layer composition type.
// - Layer hints.
@@ -363,7 +368,9 @@
void populateColorModes();
void initializeActiveConfig();
- void reallocateHwc1Contents();
+ // Creates a bi-directional mapping between index in HWC1
+ // prepare/set array and Layer object. Stores mapping in
+ // mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
void assignHwc1LayerIds();
// Called after a response to prepare() has been received:
@@ -376,13 +383,16 @@
void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
const Layer& layer);
+ // Set all fields in HWC1 comm array for layer containing the
+ // HWC_FRAMEBUFFER_TARGET (always the last layer).
void prepareFramebufferTarget();
+ // Display ID generator.
static std::atomic<hwc2_display_t> sNextId;
const hwc2_display_t mId;
- HWC2On1Adapter& mDevice;
- std::atomic<size_t> mDirtyCount;
+
+ HWC2On1Adapter& mDevice;
// The state of this display should only be modified from
// SurfaceFlinger's main loop, with the exception of when dump is
@@ -395,15 +405,18 @@
// which require locking.
mutable std::recursive_mutex mStateMutex;
- bool mZIsDirty;
+ // Allocate RAM able to store all layers and rects used for
+ // communication with HWC1. Place allocated RAM in variable
+ // mHwc1RequestedContents.
+ void allocateRequestedContents();
// Array of structs exchanged between client and hwc1 device.
- HWC1Contents mHwc1RequestedContents; // Sent to device upon calling prepare().
- HWC1Contents mHwc1ReceivedContents; // Returned by device after prepare().
-
+ // Sent to device upon calling prepare().
+ std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
+ private:
DeferredFence mRetireFence;
- // Will only be non-null after the layer has been validated but
+ // Will only be non-null after the Display has been validated and
// before it has been presented
std::unique_ptr<Changes> mChanges;
@@ -418,15 +431,34 @@
HWC2::PowerMode mPowerMode;
HWC2::Vsync mVsyncEnabled;
+ // Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
FencedBuffer mClientTarget;
+
+
FencedBuffer mOutputBuffer;
bool mHasColorTransform;
+ // All layers this Display is aware of.
std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
+
+ // Mapping between layer index in array of hwc_display_contents_1*
+ // passed to HWC1 during validate/set and Layer object.
std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
+
+ // All communication with HWC1 via prepare/set is done with one
+ // alloc. This pointer is pointing to a pool of hwc_rect_t.
+ size_t mNumAvailableRects;
+ hwc_rect_t* mNextAvailableRect;
+
+ // True if any of the Layers contained in this Display have been
+ // updated with anything other than a buffer since last call to
+ // Display::set()
+ bool mGeometryChanged;
};
+ // Utility template calling a Display object method directly based on the
+ // hwc2_display_t displayId parameter.
template <typename ...Args>
static int32_t callDisplayFunction(hwc2_device_t* device,
hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
@@ -468,7 +500,8 @@
static int32_t setColorModeHook(hwc2_device_t* device,
hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
auto mode = static_cast<android_color_mode_t>(intMode);
- return callDisplayFunction(device, display, &Display::setColorMode, mode);
+ return callDisplayFunction(device, display, &Display::setColorMode,
+ mode);
}
static int32_t setPowerModeHook(hwc2_device_t* device,
@@ -485,46 +518,6 @@
enabled);
}
- // Layer functions
-
- template <typename T>
- class LatchedState {
- public:
- LatchedState(Layer& parent, T initialValue)
- : mParent(parent),
- mPendingValue(initialValue),
- mValue(initialValue) {}
-
- void setPending(T value) {
- if (value == mPendingValue) {
- return;
- }
- if (mPendingValue == mValue) {
- mParent.incDirty();
- } else if (value == mValue) {
- mParent.decDirty();
- }
- mPendingValue = value;
- }
-
- T getValue() const { return mValue; }
- T getPendingValue() const { return mPendingValue; }
-
- bool isDirty() const { return mPendingValue != mValue; }
-
- void latch() {
- if (isDirty()) {
- mValue = mPendingValue;
- mParent.decDirty();
- }
- }
-
- private:
- Layer& mParent;
- T mPendingValue;
- T mValue;
- };
-
class Layer {
public:
explicit Layer(Display& display);
@@ -535,10 +528,6 @@
hwc2_layer_t getId() const { return mId; }
Display& getDisplay() const { return mDisplay; }
- void incDirty() { if (mDirtyCount++ == 0) mDisplay.incDirty(); }
- void decDirty() { if (--mDirtyCount == 0) mDisplay.decDirty(); }
- bool isDirty() const { return mDirtyCount > 0; }
-
// HWC2 Layer functions
HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
HWC2::Error setCursorPosition(int32_t x, int32_t y);
@@ -558,7 +547,7 @@
HWC2::Error setZ(uint32_t z);
HWC2::Composition getCompositionType() const {
- return mCompositionType.getValue();
+ return mCompositionType;
}
uint32_t getZ() const { return mZ; }
@@ -568,47 +557,57 @@
void setHwc1Id(size_t id) { mHwc1Id = id; }
size_t getHwc1Id() const { return mHwc1Id; }
- void applyState(struct hwc_layer_1& hwc1Layer, bool applyAllState);
+ // Write state to HWC1 communication struct.
+ void applyState(struct hwc_layer_1& hwc1Layer);
std::string dump() const;
+ std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
+
+ std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
+
+ // True if a layer cannot be properly rendered by the device due
+ // to usage of SolidColor (a.k.a BackgroundColor in HWC1).
+ bool hasUnsupportedBackgroundColor() {
+ return (mCompositionType == HWC2::Composition::SolidColor &&
+ !mDisplay.getDevice().supportsBackgroundColor());
+ }
private:
- void applyCommonState(struct hwc_layer_1& hwc1Layer,
- bool applyAllState);
- void applySolidColorState(struct hwc_layer_1& hwc1Layer,
- bool applyAllState);
- void applySidebandState(struct hwc_layer_1& hwc1Layer,
- bool applyAllState);
+ void applyCommonState(struct hwc_layer_1& hwc1Layer);
+ void applySolidColorState(struct hwc_layer_1& hwc1Layer);
+ void applySidebandState(struct hwc_layer_1& hwc1Layer);
void applyBufferState(struct hwc_layer_1& hwc1Layer);
- void applyCompositionType(struct hwc_layer_1& hwc1Layer,
- bool applyAllState);
+ void applyCompositionType(struct hwc_layer_1& hwc1Layer);
static std::atomic<hwc2_layer_t> sNextId;
const hwc2_layer_t mId;
Display& mDisplay;
- size_t mDirtyCount;
FencedBuffer mBuffer;
std::vector<hwc_rect_t> mSurfaceDamage;
- LatchedState<HWC2::BlendMode> mBlendMode;
- LatchedState<hwc_color_t> mColor;
- LatchedState<HWC2::Composition> mCompositionType;
- LatchedState<hwc_rect_t> mDisplayFrame;
- LatchedState<float> mPlaneAlpha;
- LatchedState<const native_handle_t*> mSidebandStream;
- LatchedState<hwc_frect_t> mSourceCrop;
- LatchedState<HWC2::Transform> mTransform;
- LatchedState<std::vector<hwc_rect_t>> mVisibleRegion;
+ HWC2::BlendMode mBlendMode;
+ hwc_color_t mColor;
+ HWC2::Composition mCompositionType;
+ hwc_rect_t mDisplayFrame;
+ float mPlaneAlpha;
+ const native_handle_t* mSidebandStream;
+ hwc_frect_t mSourceCrop;
+ HWC2::Transform mTransform;
+ std::vector<hwc_rect_t> mVisibleRegion;
+
uint32_t mZ;
DeferredFence mReleaseFence;
size_t mHwc1Id;
bool mHasUnsupportedPlaneAlpha;
- bool mHasUnsupportedBackgroundColor;
};
+ // Utility tempate calling a Layer object method based on ID parameters:
+ // hwc2_display_t displayId
+ // and
+ // hwc2_layer_t layerId
template <typename ...Args>
static int32_t callLayerFunction(hwc2_device_t* device,
hwc2_display_t displayId, hwc2_layer_t layerId,
@@ -677,6 +676,7 @@
std::vector<struct hwc_display_contents_1*> mHwc1Contents;
HWC2::Error setAllDisplays();
+ // Callbacks
void hwc1Invalidate();
void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
void hwc1Hotplug(int hwc1DisplayId, int connected);
@@ -698,6 +698,8 @@
// callbacks or dump
std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
+
+ // A HWC1 supports only one virtual display.
std::shared_ptr<Display> mHwc1VirtualDisplay;
// These are potentially accessed from multiple threads, and are protected
@@ -712,10 +714,19 @@
};
std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
bool mHasPendingInvalidate;
+
+ // There is a small gap between the time the HWC1 module is started and
+ // when the callbacks for vsync and hotplugs are registered by the
+ // HWC2on1Adapter. To prevent losing events they are stored in these arrays
+ // and fed to the callback as soon as possible.
std::vector<std::pair<int, int64_t>> mPendingVsyncs;
std::vector<std::pair<int, int>> mPendingHotplugs;
+ // Mapping between HWC1 display id and Display objects.
std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+
+ // Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
+ // HWC_DISPLAY_VIRTUAL) to Display IDs generated by HWC2on1Adapter objects.
std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
};
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index a104e8f..c953c68 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -15,7 +15,7 @@
*/
#include "Daltonizer.h"
-#include <ui/mat4.h>
+#include <math/mat4.h>
namespace android {
diff --git a/services/surfaceflinger/Effects/Daltonizer.h b/services/surfaceflinger/Effects/Daltonizer.h
index d21b155..2fb60e9 100644
--- a/services/surfaceflinger/Effects/Daltonizer.h
+++ b/services/surfaceflinger/Effects/Daltonizer.h
@@ -17,7 +17,7 @@
#ifndef SF_EFFECTS_DALTONIZER_H_
#define SF_EFFECTS_DALTONIZER_H_
-#include <ui/mat4.h>
+#include <math/mat4.h>
namespace android {
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 0259881..d19137b 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -23,7 +23,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <ui/mat4.h>
+#include <math/mat4.h>
#include <Transform.h>
#define EGL_NO_CONFIG ((EGLConfig)0)
diff --git a/services/surfaceflinger/RenderEngine/Texture.h b/services/surfaceflinger/RenderEngine/Texture.h
index 8cf85fc..a07e0c3 100644
--- a/services/surfaceflinger/RenderEngine/Texture.h
+++ b/services/surfaceflinger/RenderEngine/Texture.h
@@ -15,7 +15,7 @@
*/
#include <stdint.h>
-#include <ui/mat4.h>
+#include <math/mat4.h>
#ifndef SF_RENDER_ENGINE_TEXTURE_H
#define SF_RENDER_ENGINE_TEXTURE_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 215628d..60c71b3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -176,8 +176,10 @@
mFrameBuckets(),
mTotalTime(0),
mLastSwapTime(0),
- mNumLayers(0),
- mEnterVrMode(false)
+ mNumLayers(0)
+#ifdef USE_HWC2
+ ,mEnterVrMode(false)
+#endif
{
ALOGI("SurfaceFlinger is starting");
@@ -1204,12 +1206,17 @@
}
void SurfaceFlinger::updateVrMode() {
+ bool enteringVrMode = mEnterVrMode;
+ if (enteringVrMode == mHwc->isUsingVrComposer()) {
+ return;
+ }
+ if (enteringVrMode && !mVrHwc) {
+ // Construct new HWComposer without holding any locks.
+ mVrHwc = new HWComposer(true);
+ ALOGV("Vr HWC created");
+ }
{
Mutex::Autolock _l(mStateLock);
- bool enteringVrMode = mEnterVrMode;
- if (enteringVrMode == mHwc->isUsingVrComposer()) {
- return;
- }
if (enteringVrMode) {
// Start vrflinger thread, if it hasn't been started already.
@@ -1224,11 +1231,6 @@
}
}
- if (!mVrHwc) {
- mVrHwc = new HWComposer(true);
- ALOGV("Vr HWC created");
- }
-
resetHwc();
mHwc = mVrHwc;
@@ -2539,11 +2541,18 @@
const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
mCurrentState.layersSortedByZ.remove(layer);
- if (index < 0) {
+ // As a matter of normal operation, the LayerCleaner will produce a second
+ // attempt to remove the surface. The Layer will be kept alive in mDrawingState
+ // so we will succeed in promoting it, but it's already been removed
+ // from mCurrentState. As long as we can find it in mDrawingState we have no problem
+ // otherwise something has gone wrong and we are leaking the layer.
+ if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
ALOGE("Failed to find layer (%s) in layer parent (%s).",
layer->getName().string(),
(p != nullptr) ? p->getName().string() : "no-parent");
return BAD_VALUE;
+ } else if (index < 0) {
+ return NO_ERROR;
}
mLayersPendingRemoval.add(layer);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f52bd2d..c43786a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -40,7 +40,7 @@
#include <ui/FenceTime.h>
#include <ui/PixelFormat.h>
-#include <ui/mat4.h>
+#include <math/mat4.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e6ab29a..5aaaab1 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2325,11 +2325,18 @@
const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
mCurrentState.layersSortedByZ.remove(layer);
- if (index < 0) {
+ // As a matter of normal operation, the LayerCleaner will produce a second
+ // attempt to remove the surface. The Layer will be kept alive in mDrawingState
+ // so we will succeed in promoting it, but it's already been removed
+ // from mCurrentState. As long as we can find it in mDrawingState we have no problem
+ // otherwise something has gone wrong and we are leaking the layer.
+ if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
ALOGE("Failed to find layer (%s) in layer parent (%s).",
layer->getName().string(),
(p != nullptr) ? p->getName().string() : "no-parent");
return BAD_VALUE;
+ } else if (index < 0) {
+ return NO_ERROR;
}
mLayersPendingRemoval.add(layer);
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 66463a0..6640a13 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -22,8 +22,8 @@
#include <ui/Point.h>
#include <ui/Rect.h>
-#include <ui/vec2.h>
-#include <ui/vec3.h>
+#include <math/vec2.h>
+#include <math/vec3.h>
#include <hardware/hardware.h>
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 53a63bd..f151087 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -45,12 +45,10 @@
set_sched_policy(0, SP_FOREGROUND);
-#ifdef ENABLE_CPUSETS
// Put most SurfaceFlinger threads in the system-background cpuset
// Keeps us from unnecessarily using big cores
// Do this after the binder thread pool init
- set_cpuset_policy(0, SP_SYSTEM);
-#endif
+ if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);
// initialize before clients can connect
flinger->init();
diff --git a/services/vr/sensord/pose_service.cpp b/services/vr/sensord/pose_service.cpp
index 8e4dbba..40eb21d 100644
--- a/services/vr/sensord/pose_service.cpp
+++ b/services/vr/sensord/pose_service.cpp
@@ -62,6 +62,7 @@
static constexpr char kEnableSensorPlayProp[] = "dvr.enable_6dof_playback";
static constexpr char kEnableSensorPlayIdProp[] = "dvr.6dof_playback_id";
static constexpr char kEnablePoseRecordProp[] = "dvr.enable_pose_recording";
+static constexpr char kPredictorTypeProp[] = "dvr.predictor_type";
// Persistent buffer names.
static constexpr char kPoseRingBufferName[] = "PoseService:RingBuffer";
@@ -229,6 +230,15 @@
}
}
+ switch (property_get_int32(kPredictorTypeProp, 0)) {
+ case 1:
+ pose_predictor_ = posepredictor::Predictor::Create(
+ posepredictor::PredictorType::Quadric);
+ default:
+ pose_predictor_ = posepredictor::Predictor::Create(
+ posepredictor::PredictorType::Linear);
+ }
+
enable_pose_recording_ = property_get_bool(kEnablePoseRecordProp, 0) == 1;
SetPoseMode(DVR_POSE_MODE_6DOF);
@@ -326,10 +336,8 @@
pose_timestamp = GetSystemClockNs() - 1;
// Feed the sample to the predictor
- pose_predictor_.Add(PosePredictor::Sample{.position = start_t_head,
- .orientation = start_q_head,
- .time_ns = pose_timestamp},
- &last_known_pose_);
+ AddPredictorPose(pose_predictor_.get(), start_t_head, start_q_head,
+ pose_timestamp, &last_known_pose_);
// Store one extra value, because the application is working on the next
// frame and expects the minimum count from that frame on.
@@ -351,9 +359,9 @@
// Make a pose prediction
if (enable_pose_prediction_) {
- pose_predictor_.Predict(target_time,
- target_time + right_eye_photon_offset_ns_,
- mapped_pose_buffer_->ring + index);
+ PredictPose(pose_predictor_.get(), target_time,
+ target_time + right_eye_photon_offset_ns_,
+ mapped_pose_buffer_->ring + index);
} else {
mapped_pose_buffer_->ring[index] = last_known_pose_;
}
diff --git a/services/vr/sensord/pose_service.h b/services/vr/sensord/pose_service.h
index 300737c..899d5fb 100644
--- a/services/vr/sensord/pose_service.h
+++ b/services/vr/sensord/pose_service.h
@@ -12,8 +12,8 @@
#include <pdx/service.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/pose_client_internal.h>
+#include <private/dvr/dvr_pose_predictor.h>
#include <private/dvr/ring_buffer.h>
-#include <private/dvr/linear_pose_predictor.h>
#include "sensor_fusion.h"
#include "sensor_thread.h"
@@ -118,7 +118,7 @@
bool enable_external_pose_ = false;
// The predictor to extrapolate pose samples.
- LinearPosePredictor pose_predictor_;
+ std::unique_ptr<posepredictor::Predictor> pose_predictor_;
// Pose ring buffer.
std::shared_ptr<BufferProducer> ring_buffer_;
diff --git a/services/vr/sensord/sensor_ndk_thread.cpp b/services/vr/sensord/sensor_ndk_thread.cpp
index 815453b..9c3abbc 100644
--- a/services/vr/sensord/sensor_ndk_thread.cpp
+++ b/services/vr/sensord/sensor_ndk_thread.cpp
@@ -37,11 +37,10 @@
// Start ALooper and initialize sensor access.
{
std::unique_lock<std::mutex> lock(mutex_);
- initialization_result_ = InitializeSensors();
+ InitializeSensors();
thread_started_ = true;
init_condition_.notify_one();
- if (!initialization_result_)
- return;
+ // Continue on failure - the loop below will periodically retry.
}
EventConsumer consumer;
@@ -61,7 +60,7 @@
constexpr int kMaxEvents = 100;
sensors_event_t events[kMaxEvents];
ssize_t event_count = 0;
- if (looper_ && sensor_manager_) {
+ if (initialization_result_) {
int poll_fd, poll_events;
void* poll_source;
// Poll for events.
@@ -79,7 +78,6 @@
// This happens when sensorservice has died and restarted. To avoid
// spinning we need to restart the sensor access.
DestroySensors();
- InitializeSensors();
}
} else {
// When there is no sensor_device_, we still call the consumer at
@@ -114,7 +112,8 @@
}
// At this point, we've successfully initialized everything.
- *out_success = initialization_result_;
+ // The NDK sensor thread will continue to retry on error, so assume success here.
+ *out_success = true;
}
SensorNdkThread::~SensorNdkThread() {
@@ -167,10 +166,13 @@
}
}
+ initialization_result_ = true;
return true;
}
void SensorNdkThread::DestroySensors() {
+ if (!event_queue_)
+ return;
for (size_t sensor_index = 0; sensor_index < sensor_user_count_.size();
++sensor_index) {
if (sensor_user_count_[sensor_index] > 0) {
@@ -178,9 +180,19 @@
}
}
ASensorManager_destroyEventQueue(sensor_manager_, event_queue_);
+ event_queue_ = nullptr;
+ initialization_result_ = false;
}
void SensorNdkThread::UpdateSensorUse() {
+ if (!initialization_result_) {
+ // Sleep for 1 second to avoid spinning during system instability.
+ usleep(1000 * 1000);
+ InitializeSensors();
+ if (!initialization_result_)
+ return;
+ }
+
if (!enable_sensors_.empty()) {
for (int sensor_index : enable_sensors_) {
if (sensor_user_count_[sensor_index]++ == 0) {
diff --git a/services/vr/vr_window_manager/composer/1.0/Android.bp b/services/vr/vr_window_manager/composer/1.0/Android.bp
index e3e47ff..58f83f8 100644
--- a/services/vr/vr_window_manager/composer/1.0/Android.bp
+++ b/services/vr/vr_window_manager/composer/1.0/Android.bp
@@ -6,13 +6,9 @@
cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hidl:system/libhidl/transport -randroid.hardware:hardware/interfaces/ -randroid.dvr:frameworks/native/services/vr/vr_window_manager android.dvr.composer@1.0",
srcs: [
"IVrComposerClient.hal",
- "IVrComposerView.hal",
- "IVrComposerCallback.hal",
],
out: [
"android/dvr/composer/1.0/VrComposerClientAll.cpp",
- "android/dvr/composer/1.0/VrComposerViewAll.cpp",
- "android/dvr/composer/1.0/VrComposerCallbackAll.cpp",
],
}
@@ -22,27 +18,13 @@
cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hidl:system/libhidl/transport -randroid.hardware:hardware/interfaces/ -randroid.dvr:frameworks/native/services/vr/vr_window_manager android.dvr.composer@1.0",
srcs: [
"IVrComposerClient.hal",
- "IVrComposerView.hal",
- "IVrComposerCallback.hal",
],
out: [
"android/dvr/composer/1.0/IVrComposerClient.h",
"android/dvr/composer/1.0/IHwVrComposerClient.h",
- "android/dvr/composer/1.0/BnVrComposerClient.h",
- "android/dvr/composer/1.0/BpVrComposerClient.h",
+ "android/dvr/composer/1.0/BnHwVrComposerClient.h",
+ "android/dvr/composer/1.0/BpHwVrComposerClient.h",
"android/dvr/composer/1.0/BsVrComposerClient.h",
-
- "android/dvr/composer/1.0/IVrComposerView.h",
- "android/dvr/composer/1.0/IHwVrComposerView.h",
- "android/dvr/composer/1.0/BnVrComposerView.h",
- "android/dvr/composer/1.0/BpVrComposerView.h",
- "android/dvr/composer/1.0/BsVrComposerView.h",
-
- "android/dvr/composer/1.0/IVrComposerCallback.h",
- "android/dvr/composer/1.0/IHwVrComposerCallback.h",
- "android/dvr/composer/1.0/BnVrComposerCallback.h",
- "android/dvr/composer/1.0/BpVrComposerCallback.h",
- "android/dvr/composer/1.0/BsVrComposerCallback.h",
],
}
diff --git a/services/vr/vr_window_manager/composer/1.0/IVrComposerCallback.hal b/services/vr/vr_window_manager/composer/1.0/IVrComposerCallback.hal
deleted file mode 100644
index 6e7255e..0000000
--- a/services/vr/vr_window_manager/composer/1.0/IVrComposerCallback.hal
+++ /dev/null
@@ -1,18 +0,0 @@
-package android.dvr.composer@1.0;
-
-import android.hardware.graphics.composer@2.1::IComposerClient;
-
-interface IVrComposerCallback {
- struct Layer {
- handle buffer;
- handle fence;
- android.hardware.graphics.composer@2.1::IComposerClient.Rect display_frame;
- android.hardware.graphics.composer@2.1::IComposerClient.FRect crop;
- android.hardware.graphics.composer@2.1::IComposerClient.BlendMode blend_mode;
- float alpha;
- uint32_t type;
- uint32_t app_id;
- };
-
- onNewFrame(vec<Layer> frame);
-};
diff --git a/services/vr/vr_window_manager/composer/1.0/IVrComposerView.hal b/services/vr/vr_window_manager/composer/1.0/IVrComposerView.hal
deleted file mode 100644
index e16131a..0000000
--- a/services/vr/vr_window_manager/composer/1.0/IVrComposerView.hal
+++ /dev/null
@@ -1,9 +0,0 @@
-package android.dvr.composer@1.0;
-
-import IVrComposerCallback;
-
-interface IVrComposerView {
- registerCallback(IVrComposerCallback callback);
-
- releaseFrame();
-};
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index 08c105c..7c8bb86 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -6,7 +6,6 @@
name: "libvrhwc",
srcs: [
- "impl/sync_timeline.cpp",
"impl/vr_composer_view.cpp",
"impl/vr_hwc.cpp",
"impl/vr_composer_client.cpp",
@@ -33,11 +32,6 @@
export_include_dirs: ["."],
- include_dirs: [
- // Access to software sync timeline.
- "system/core/libsync",
- ],
-
cflags: [
"-DLOG_TAG=\"vrhwc\"",
],
diff --git a/services/vr/vr_window_manager/composer/impl/sync_timeline.cpp b/services/vr/vr_window_manager/composer/impl/sync_timeline.cpp
deleted file mode 100644
index e63ed26..0000000
--- a/services/vr/vr_window_manager/composer/impl/sync_timeline.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2016 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 "sync_timeline.h"
-
-#include <sys/cdefs.h>
-#include <sw_sync.h>
-#include <unistd.h>
-
-namespace android {
-namespace dvr {
-
-SyncTimeline::SyncTimeline() {}
-
-SyncTimeline::~SyncTimeline() {}
-
-bool SyncTimeline::Initialize() {
- timeline_fd_.reset(sw_sync_timeline_create());
- return timeline_fd_ >= 0;
-}
-
-int SyncTimeline::CreateFence(int time) {
- return sw_sync_fence_create(timeline_fd_.get(), "dummy fence", time);
-}
-
-bool SyncTimeline::IncrementTimeline() {
- return sw_sync_timeline_inc(timeline_fd_.get(), 1) == 0;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/vr_window_manager/composer/impl/sync_timeline.h b/services/vr/vr_window_manager/composer/impl/sync_timeline.h
deleted file mode 100644
index 945acbd..0000000
--- a/services/vr/vr_window_manager/composer/impl/sync_timeline.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-#ifndef VR_WINDOW_MANAGER_COMPOSER_IMPL_SYNC_TIMELINE_H_
-#define VR_WINDOW_MANAGER_COMPOSER_IMPL_SYNC_TIMELINE_H_
-
-#include <android-base/unique_fd.h>
-
-namespace android {
-namespace dvr {
-
-// TODO(dnicoara): Remove this and move to EGL based fences.
-class SyncTimeline {
- public:
- SyncTimeline();
- ~SyncTimeline();
-
- bool Initialize();
-
- int CreateFence(int time);
- bool IncrementTimeline();
-
- private:
- base::unique_fd timeline_fd_;
-
- SyncTimeline(const SyncTimeline&) = delete;
- void operator=(const SyncTimeline&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // VR_WINDOW_MANAGER_COMPOSER_IMPL_SYNC_TIMELINE_H_
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp b/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
index 1096a37..299e8f1 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
@@ -16,19 +16,12 @@
composer_view_->RegisterObserver(this);
}
-void VrComposerView::ReleaseFrame() {
- LOG_ALWAYS_FATAL_IF(!composer_view_, "VrComposerView not initialized");
- composer_view_->ReleaseFrame();
-}
-
-void VrComposerView::OnNewFrame(const ComposerView::Frame& frame) {
+base::unique_fd VrComposerView::OnNewFrame(const ComposerView::Frame& frame) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!callback_.get()) {
- ReleaseFrame();
- return;
- }
+ if (!callback_.get())
+ return base::unique_fd();
- callback_->OnNewFrame(frame);
+ return callback_->OnNewFrame(frame);
}
} // namespace dvr
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_view.h b/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
index 5a938e9..8c5ee1f 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
@@ -13,7 +13,7 @@
class Callback {
public:
virtual ~Callback() = default;
- virtual void OnNewFrame(const ComposerView::Frame& frame) = 0;
+ virtual base::unique_fd OnNewFrame(const ComposerView::Frame& frame) = 0;
};
VrComposerView(std::unique_ptr<Callback> callback);
@@ -21,10 +21,8 @@
void Initialize(ComposerView* composer_view);
- void ReleaseFrame();
-
// ComposerView::Observer
- void OnNewFrame(const ComposerView::Frame& frame) override;
+ base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
private:
ComposerView* composer_view_;
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 9642224..6a78c98 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -21,7 +21,6 @@
#include <mutex>
-#include "sync_timeline.h"
#include "vr_composer_client.h"
using namespace android::hardware::graphics::common::V1_0;
@@ -48,6 +47,7 @@
int32_t format = 0;
GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+ // Need to register |handle| otherwise we can't read its properties.
if (mapper.registerBuffer(handle) != OK) {
ALOGE("Failed to register buffer");
return nullptr;
@@ -66,9 +66,15 @@
// capability. Otherwise assume a count of 1.
mapper.getLayerCount(handle, &layer_count);
+ // NOTE: Can't re-use |handle| since we don't own it.
sp<GraphicBuffer> buffer = new GraphicBuffer(
width, height, format, layer_count, producer_usage, consumer_usage,
stride, native_handle_clone(handle), true);
+ // Need to register the cloned buffer otherwise it can't be used later on.
+ if (mapper.registerBuffer(buffer.get()) != OK) {
+ ALOGE("Failed to register cloned buffer");
+ return nullptr;
+ }
return buffer;
}
@@ -79,8 +85,6 @@
HwcDisplay::~HwcDisplay() {}
-bool HwcDisplay::Initialize() { return hwc_timeline_.Initialize(); }
-
bool HwcDisplay::SetClientTarget(const native_handle_t* handle,
base::unique_fd fence) {
if (handle)
@@ -98,14 +102,14 @@
HwcLayer* HwcDisplay::GetLayer(Layer id) {
for (size_t i = 0; i < layers_.size(); ++i)
- if (layers_[i].id == id) return &layers_[i];
+ if (layers_[i].info.id == id) return &layers_[i];
return nullptr;
}
bool HwcDisplay::DestroyLayer(Layer id) {
for (auto it = layers_.begin(); it != layers_.end(); ++it) {
- if (it->id == id) {
+ if (it->info.id == id) {
layers_.erase(it);
return true;
}
@@ -141,7 +145,7 @@
for (size_t i = 0; i < layers_.size(); ++i) {
if (i >= first_client_layer && i <= last_client_layer) {
if (layers_[i].composition_type != IComposerClient::Composition::CLIENT) {
- layer_ids->push_back(layers_[i].id);
+ layer_ids->push_back(layers_[i].info.id);
types->push_back(IComposerClient::Composition::CLIENT);
layers_[i].composition_type = IComposerClient::Composition::CLIENT;
}
@@ -150,7 +154,7 @@
}
if (layers_[i].composition_type != IComposerClient::Composition::DEVICE) {
- layer_ids->push_back(layers_[i].id);
+ layer_ids->push_back(layers_[i].info.id);
types->push_back(IComposerClient::Composition::DEVICE);
layers_[i].composition_type = IComposerClient::Composition::DEVICE;
}
@@ -198,26 +202,18 @@
return Error::BAD_LAYER;
}
- // Increment the time the fence is signalled every time we get the
- // presentation frame. This ensures that calling ReleaseFrame() only affects
- // the current frame.
- fence_time_++;
out_frames->swap(frame);
return Error::NONE;
}
-void HwcDisplay::GetReleaseFences(int* present_fence,
- std::vector<Layer>* layer_ids,
- std::vector<int>* fences) {
- *present_fence = hwc_timeline_.CreateFence(fence_time_);
- for (const auto& layer : layers_) {
- layer_ids->push_back(layer.id);
- fences->push_back(hwc_timeline_.CreateFence(fence_time_));
- }
-}
+std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() {
+ std::vector<Layer> last_frame_layers;
+ last_frame_layers.swap(last_frame_layers_ids_);
-void HwcDisplay::ReleaseFrame() {
- hwc_timeline_.IncrementTimeline();
+ for (const auto& layer : layers_)
+ last_frame_layers_ids_.push_back(layer.info.id);
+
+ return last_frame_layers;
}
////////////////////////////////////////////////////////////////////////////////
@@ -227,8 +223,6 @@
VrHwc::~VrHwc() {}
-bool VrHwc::Initialize() { return display_.Initialize(); }
-
bool VrHwc::hasCapability(Capability capability) const { return false; }
void VrHwc::removeClient() {
@@ -263,7 +257,7 @@
std::lock_guard<std::mutex> guard(mutex_);
HwcLayer* layer = display_.CreateLayer();
- *outLayer = layer->id;
+ *outLayer = layer->info.id;
return Error::NONE;
}
@@ -449,24 +443,33 @@
std::vector<Layer>* outLayers,
std::vector<int32_t>* outReleaseFences) {
*outPresentFence = -1;
+ outLayers->clear();
+ outReleaseFences->clear();
+
if (display != kDefaultDisplayId) {
return Error::BAD_DISPLAY;
}
std::vector<ComposerView::ComposerLayer> frame;
- {
- std::lock_guard<std::mutex> guard(mutex_);
- Error status = display_.GetFrame(&frame);
- if (status != Error::NONE)
- return status;
+ std::vector<Layer> last_frame_layers;
+ std::lock_guard<std::mutex> guard(mutex_);
+ Error status = display_.GetFrame(&frame);
+ if (status != Error::NONE)
+ return status;
- display_.GetReleaseFences(outPresentFence, outLayers, outReleaseFences);
- }
+ last_frame_layers = display_.UpdateLastFrameAndGetLastFrameLayers();
+ base::unique_fd fence;
if (observer_)
- observer_->OnNewFrame(frame);
- else
- ReleaseFrame();
+ fence = observer_->OnNewFrame(frame);
+
+ if (fence.get() < 0)
+ return Error::NONE;
+
+ *outPresentFence = dup(fence.get());
+ outLayers->swap(last_frame_layers);
+ for (size_t i = 0; i < outLayers->size(); ++i)
+ outReleaseFences->push_back(dup(fence.get()));
return Error::NONE;
}
@@ -662,11 +665,6 @@
observer_ = nullptr;
}
-void VrHwc::ReleaseFrame() {
- std::lock_guard<std::mutex> guard(mutex_);
- display_.ReleaseFrame();
-}
-
ComposerView* GetComposerViewFromIComposer(
hardware::graphics::composer::V2_1::IComposer* composer) {
return static_cast<VrHwc*>(composer);
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index 9450097..df09687 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -16,6 +16,7 @@
#ifndef VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_HWC_H_
#define VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_HWC_H_
+#include <android-base/unique_fd.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <ComposerBase.h>
#include <ui/Fence.h>
@@ -24,8 +25,6 @@
#include <mutex>
-#include "sync_timeline.h"
-
using namespace android::hardware::graphics::common::V1_0;
using namespace android::hardware::graphics::composer::V2_1;
@@ -57,6 +56,7 @@
// TODO(dnicoara): Add all layer properties. For now just the basics to get
// it going.
+ Layer id;
sp<GraphicBuffer> buffer;
sp<Fence> fence;
Recti display_frame;
@@ -75,25 +75,23 @@
// Returns a list of layers that need to be shown together. Layers are
// returned in z-order, with the lowest layer first.
- virtual void OnNewFrame(const Frame& frame) = 0;
+ virtual base::unique_fd OnNewFrame(const Frame& frame) = 0;
};
virtual ~ComposerView() {}
virtual void RegisterObserver(Observer* observer) = 0;
virtual void UnregisterObserver(Observer* observer) = 0;
-
- // Called to release the oldest frame received by the observer.
- virtual void ReleaseFrame() = 0;
};
struct HwcLayer {
using Composition =
hardware::graphics::composer::V2_1::IComposerClient::Composition;
- HwcLayer(Layer new_id) : id(new_id) {}
+ HwcLayer(Layer new_id) {
+ info.id = new_id;
+ }
- Layer id;
Composition composition_type;
uint32_t z_order;
ComposerView::ComposerLayer info;
@@ -104,8 +102,6 @@
HwcDisplay();
~HwcDisplay();
- bool Initialize();
-
HwcLayer* CreateLayer();
bool DestroyLayer(Layer id);
HwcLayer* GetLayer(Layer id);
@@ -118,10 +114,7 @@
Error GetFrame(std::vector<ComposerView::ComposerLayer>* out_frame);
- void GetReleaseFences(int* present_fence, std::vector<Layer>* layer_ids,
- std::vector<int>* fences);
-
- void ReleaseFrame();
+ std::vector<Layer> UpdateLastFrameAndGetLastFrameLayers();
private:
// The client target buffer and the associated fence.
@@ -132,19 +125,11 @@
// List of currently active layers.
std::vector<HwcLayer> layers_;
+ std::vector<Layer> last_frame_layers_ids_;
+
// Layer ID generator.
uint64_t layer_ids_ = 1;
- // Creates software sync fences used to signal releasing frames.
- SyncTimeline hwc_timeline_;
-
- // Keeps track of the current fence time. Used in conjunction with
- // |hwc_timeline_| to properly signal frame release times. Allows the observer
- // to receive multiple presentation frames without calling ReleaseFrame() in
- // between each presentation. When the observer is ready to release a frame
- // only the oldest presentation frame is affected by the release.
- int fence_time_ = 0;
-
HwcDisplay(const HwcDisplay&) = delete;
void operator=(const HwcDisplay&) = delete;
};
@@ -154,8 +139,6 @@
VrHwc();
~VrHwc() override;
- bool Initialize();
-
bool hasCapability(Capability capability) const;
Error setLayerInfo(Display display, Layer layer, uint32_t type,
@@ -246,7 +229,6 @@
// ComposerView:
void RegisterObserver(Observer* observer) override;
void UnregisterObserver(Observer* observer) override;
- void ReleaseFrame() override;
private:
wp<VrComposerClient> client_;
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index d3cd38c..05ec64a 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,7 +38,7 @@
HwcCallback::~HwcCallback() {
}
-void HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
+base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
std::vector<HwcLayer> hwc_frame(frame.size());
for (size_t i = 0; i < frame.size(); ++i) {
hwc_frame[i] = HwcLayer{
@@ -53,7 +53,8 @@
};
}
- client_->OnFrame(std::make_unique<Frame>(std::move(hwc_frame)));
+ return client_->OnFrame(
+ std::make_unique<Frame>(std::move(hwc_frame)));
}
HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index d4d6e66..bcfeb97 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -6,6 +6,7 @@
#include <mutex>
#include <vector>
+#include <android-base/unique_fd.h>
#include <impl/vr_composer_view.h>
#include <impl/vr_hwc.h>
@@ -79,14 +80,15 @@
class Client {
public:
virtual ~Client() {}
- virtual void OnFrame(std::unique_ptr<Frame>) = 0;
+ virtual base::unique_fd OnFrame(std::unique_ptr<Frame>) = 0;
};
explicit HwcCallback(Client* client);
~HwcCallback() override;
private:
- void OnNewFrame(const ComposerView::Frame& frame) override;
+ base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+
Client *client_;
HwcCallback(const HwcCallback&) = delete;
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 84b8467..9d0aaad 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -319,10 +319,6 @@
frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
current_frame_ = std::move(frame);
pending_frames_.pop_front();
-
- for(int i = 0; i < skipped_frame_count_ + 1; i++)
- surface_flinger_view_->ReleaseFrame();
- skipped_frame_count_ = 0;
}
}
}
@@ -392,7 +388,7 @@
return true;
}
-void ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
+base::unique_fd ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
ViewMode visibility =
CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
@@ -409,7 +405,6 @@
pending_frames_.emplace_back(std::move(frame), visibility);
if (pending_frames_.size() > kMaximumPendingFrames) {
- skipped_frame_count_++;
pending_frames_.pop_front();
}
@@ -427,6 +422,8 @@
QueueTask(MainThreadTask::EnteringVrMode);
QueueTask(MainThreadTask::Show);
}
+
+ return base::unique_fd(dup(release_fence_.get()));
}
bool ShellView::IsHit(const vec3& view_location, const vec3& view_direction,
@@ -518,6 +515,20 @@
DrawIme();
}
+
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID,
+ nullptr);
+ if (sync != EGL_NO_SYNC_KHR) {
+ // Need to flush in order to get the fence FD.
+ glFlush();
+ base::unique_fd fence(eglDupNativeFenceFDANDROID(display, sync));
+ eglDestroySyncKHR(display, sync);
+ UpdateReleaseFence(std::move(fence));
+ } else {
+ ALOGE("Failed to create sync fence");
+ UpdateReleaseFence(base::unique_fd());
+ }
}
void ShellView::DrawIme() {
@@ -744,5 +755,10 @@
return true;
}
+void ShellView::UpdateReleaseFence(base::unique_fd fence) {
+ std::lock_guard<std::mutex> guard(pending_frame_mutex_);
+ release_fence_ = std::move(fence);
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 39b5451..1e061bb 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -69,16 +69,15 @@
void AdvanceFrame();
+ void UpdateReleaseFence(base::unique_fd fence);
+
// HwcCallback::Client:
- void OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
+ base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
std::unique_ptr<ShaderProgram> program_;
std::unique_ptr<ShaderProgram> overlay_program_;
std::unique_ptr<ShaderProgram> controller_program_;
- // This starts at -1 so we don't call ReleaseFrame for the first frame.
- int skipped_frame_count_ = -1;
-
uint32_t current_vr_app_;
// Used to center the scene when the shell becomes visible.
@@ -126,6 +125,8 @@
mat4 controller_translate_;
+ base::unique_fd release_fence_;
+
ShellView(const ShellView&) = delete;
void operator=(const ShellView&) = delete;
};
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index d42d3ff..63bc143 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -84,9 +84,5 @@
return true;
}
-void SurfaceFlingerView::ReleaseFrame() {
- vr_composer_view_->ReleaseFrame();
-}
-
} // namespace dvr
} // namespace android
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 9c16192..7370299 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -36,8 +36,6 @@
TextureLayer* ime_layer, bool debug,
bool skip_first_layer) const;
- void ReleaseFrame();
-
private:
sp<IComposer> vr_hwcomposer_;
std::unique_ptr<VrComposerView> vr_composer_view_;