Merge "Define shared memory NDK API"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index ce0caed..8f2dee1 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -552,17 +552,13 @@
hidl_string instanceName = fqInstanceName.substr(n+1, std::string::npos);
Return<sp<IBase>> interfaceRet = sm->get(fqInterfaceName, instanceName);
if (!interfaceRet.isOk()) {
- fprintf(stderr, "failed to get service %s: %s\n",
- fqInstanceName.c_str(),
- interfaceRet.description().c_str());
+ // ignore
continue;
}
sp<IBase> interface = interfaceRet;
auto notifyRet = interface->notifySyspropsChanged();
if (!notifyRet.isOk()) {
- fprintf(stderr, "failed to notifySyspropsChanged on service %s: %s\n",
- fqInstanceName.c_str(),
- notifyRet.description().c_str());
+ // ignore
}
}
});
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e33f099..3c019ac 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -960,7 +960,7 @@
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
- RunCommand("HARDWARE HALS", {"lshal"});
+ RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::AS_ROOT);
RunCommand("PRINTENV", {"printenv"});
RunCommand("NETSTAT", {"netstat", "-nW"});
@@ -1161,7 +1161,7 @@
printf("== Board\n");
printf("========================================================\n");
- ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService("dumpstate"));
+ ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
if (dumpstate_device == nullptr) {
MYLOGE("No IDumpstateDevice implementation\n");
return;
@@ -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/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk
index 3ec3178..1dd926c 100644
--- a/cmds/surfacereplayer/replayer/Android.mk
+++ b/cmds/surfacereplayer/replayer/Android.mk
@@ -42,6 +42,7 @@
libutils \
libprotobuf-cpp-lite \
libbase \
+ libnativewindow \
LOCAL_STATIC_LIBRARIES := \
libtrace_proto \
@@ -61,6 +62,7 @@
libprotobuf-cpp-lite \
libsurfacereplayer \
libutils \
+ libgui \
LOCAL_STATIC_LIBRARIES := \
libtrace_proto \
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/android/multinetwork.h b/include/android/multinetwork.h
index be01518..97892f8 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -56,12 +56,10 @@
/**
* Set the network to be used by the given socket file descriptor.
*
- * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED.
+ * To clear a previous socket binding, invoke with NETWORK_UNSPECIFIED.
*
- * This is the equivalent of:
+ * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket))
*
- * [ android.net.Network#bindSocket() ]
- * https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket)
*/
int android_setsocknetwork(net_handle_t network, int fd);
@@ -75,12 +73,10 @@
* resolutions will fail. This is by design so an application doesn't
* accidentally use sockets it thinks are still bound to a particular network.
*
- * To clear a previous process binding invoke with NETWORK_UNSPECIFIED.
+ * To clear a previous process binding, invoke with NETWORK_UNSPECIFIED.
*
- * This is the equivalent of:
+ * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
*
- * [ android.net.ConnectivityManager#setProcessDefaultNetwork() ]
- * https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)
*/
int android_setprocnetwork(net_handle_t network);
@@ -96,10 +92,8 @@
* - either |node| or |service| may be NULL, but not both
* - |res| must not be NULL
*
- * This is the equivalent of:
+ * This is the equivalent of: [android.net.Network#getAllByName()](https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String))
*
- * [ android.net.Network#getAllByName() ]
- * https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String)
*/
int android_getaddrinfofornetwork(net_handle_t network,
const char *node, const char *service,
diff --git a/include/android/trace.h b/include/android/trace.h
index 6cdcfeb..d3b1fb6 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -14,6 +14,13 @@
* limitations under the License.
*/
+/**
+ * @file trace.h
+ * @brief Writes trace events to the system trace buffer.
+ *
+ * These trace events can be collected and visualized using the Systrace tool.
+ * For information about using the Systrace tool, read <a href="https://developer.android.com/studio/profile/systrace.html">Analyzing UI Performance with Systrace</a>.
+ */
#ifndef ANDROID_NATIVE_TRACE_H
#define ANDROID_NATIVE_TRACE_H
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 56c7a3f..ec77ec7 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -18,18 +18,13 @@
#define ANDROID_GUI_BUFFERITEMCONSUMER_H
#include <gui/ConsumerBase.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
+#include <gui/BufferQueue.h>
#define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer"
namespace android {
-class BufferQueue;
+class String8;
/**
* BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index a523cd8..c95c535 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -62,11 +62,12 @@
public:
explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
virtual ~ProxyConsumerListener();
- virtual void onFrameAvailable(const BufferItem& item) override;
- virtual void onFrameReplaced(const BufferItem& item) override;
- virtual void onBuffersReleased() override;
- virtual void onSidebandStreamChanged() override;
- virtual void addAndGetFrameTimestamps(
+ void onDisconnect() override;
+ void onFrameAvailable(const BufferItem& item) override;
+ void onFrameReplaced(const BufferItem& item) override;
+ void onBuffersReleased() override;
+ void onSidebandStreamChanged() override;
+ void addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
private:
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index ce85fc3..7912528 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -17,19 +17,23 @@
#ifndef ANDROID_GUI_CONSUMERBASE_H
#define ANDROID_GUI_CONSUMERBASE_H
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/OccupancyTracker.h>
-#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>
-#include <gui/IConsumerListener.h>
+
namespace android {
// ----------------------------------------------------------------------------
class String8;
+class GraphicBuffer;
// ConsumerBase is a base class for BufferQueue consumer end-points. It
// handles common tasks like management of the connection to the BufferQueue
@@ -222,7 +226,7 @@
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
- Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS];
+ Slot mSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
// mAbandoned indicates that the BufferQueue will no longer be used to
// consume images buffers pushed to it using the IGraphicBufferProducer
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index b7aa463..58602bf 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -17,18 +17,19 @@
#ifndef ANDROID_GUI_CPUCONSUMER_H
#define ANDROID_GUI_CPUCONSUMER_H
+#include <system/window.h>
+
#include <gui/ConsumerBase.h>
+#include <gui/BufferQueue.h>
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
#include <utils/Vector.h>
-#include <utils/threads.h>
namespace android {
class BufferQueue;
+class GraphicBuffer;
+class String8;
/**
* CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 9e1ae94..bda3c5c 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -41,7 +41,7 @@
ACQUIRE,
FIRST_REFRESH_START,
LAST_REFRESH_START,
- GL_COMPOSITION_DONE,
+ GPU_COMPOSITION_DONE,
DISPLAY_PRESENT,
DISPLAY_RETIRE,
DEQUEUE_READY,
@@ -52,6 +52,16 @@
// A collection of timestamps corresponding to a single frame.
struct FrameEvents {
+ static constexpr auto EVENT_COUNT =
+ static_cast<size_t>(FrameEvent::EVENT_COUNT);
+ static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
+ static constexpr nsecs_t TIMESTAMP_PENDING =
+ std::numeric_limits<nsecs_t>::max();
+
+ static inline bool isValidTimestamp(nsecs_t time) {
+ return time != TIMESTAMP_PENDING;
+ }
+
bool hasPostedInfo() const;
bool hasRequestedPresentInfo() const;
bool hasLatchInfo() const;
@@ -67,11 +77,8 @@
void checkFencesForCompletion();
void dump(String8& outString) const;
- static constexpr size_t EVENT_COUNT =
- static_cast<size_t>(FrameEvent::EVENT_COUNT);
- static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
-
bool valid{false};
+ int connectId{0};
uint64_t frameNumber{0};
// Whether or not certain points in the frame's life cycle have been
@@ -81,12 +88,12 @@
bool addRetireCalled{false};
bool addReleaseCalled{false};
- nsecs_t postedTime{-1};
- nsecs_t requestedPresentTime{-1};
- nsecs_t latchTime{-1};
- nsecs_t firstRefreshStartTime{-1};
- nsecs_t lastRefreshStartTime{-1};
- nsecs_t dequeueReadyTime{-1};
+ nsecs_t postedTime{TIMESTAMP_PENDING};
+ nsecs_t requestedPresentTime{TIMESTAMP_PENDING};
+ nsecs_t latchTime{TIMESTAMP_PENDING};
+ nsecs_t firstRefreshStartTime{TIMESTAMP_PENDING};
+ nsecs_t lastRefreshStartTime{TIMESTAMP_PENDING};
+ nsecs_t dequeueReadyTime{TIMESTAMP_PENDING};
std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
@@ -206,6 +213,8 @@
public:
~ConsumerFrameEventHistory() override;
+ void onDisconnect();
+
void initializeCompositorTiming(const CompositorTiming& compositorTiming);
void addQueue(const NewFrameEventsEntry& newEntry);
@@ -227,11 +236,13 @@
const std::array<FrameEvents, MAX_FRAME_HISTORY>::iterator& frame);
std::array<FrameEventDirtyFields, MAX_FRAME_HISTORY> mFramesDirty;
+
size_t mQueueOffset{0};
size_t mCompositionOffset{0};
size_t mRetireOffset{0};
size_t mReleaseOffset{0};
+ int mCurrentConnectId{0};
bool mProducerWantsEvents{false};
};
@@ -273,12 +284,12 @@
bool mAddRetireCalled{0};
bool mAddReleaseCalled{0};
- nsecs_t mPostedTime{0};
- nsecs_t mRequestedPresentTime{0};
- nsecs_t mLatchTime{0};
- nsecs_t mFirstRefreshStartTime{0};
- nsecs_t mLastRefreshStartTime{0};
- nsecs_t mDequeueReadyTime{0};
+ nsecs_t mPostedTime{FrameEvents::TIMESTAMP_PENDING};
+ nsecs_t mRequestedPresentTime{FrameEvents::TIMESTAMP_PENDING};
+ nsecs_t mLatchTime{FrameEvents::TIMESTAMP_PENDING};
+ nsecs_t mFirstRefreshStartTime{FrameEvents::TIMESTAMP_PENDING};
+ nsecs_t mLastRefreshStartTime{FrameEvents::TIMESTAMP_PENDING};
+ nsecs_t mDequeueReadyTime{FrameEvents::TIMESTAMP_PENDING};
FenceTime::Snapshot mGpuCompositionDoneFence;
FenceTime::Snapshot mDisplayPresentFence;
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 4a49f53..51d7666 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -20,8 +20,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
#include <gui/ConsumerBase.h>
#include <ui/GraphicBuffer.h>
@@ -489,7 +488,7 @@
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
- EglSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
+ EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
// mCurrentTexture is the buffer slot index of the buffer that is currently
// bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 93dd4ac..a3c7d64 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -43,6 +43,9 @@
ConsumerListener() { }
virtual ~ConsumerListener();
+ // onDisconnect is called when a producer disconnects from the BufferQueue.
+ virtual void onDisconnect() {} /* Asynchronous */
+
// onFrameAvailable is called from queueBuffer each time an additional
// frame becomes available for consumption. This means that frames that
// are queued while in asynchronous mode only trigger the callback if no
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index dcddca4..60b7d24 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -25,8 +25,9 @@
#include <utils/Timers.h>
#include <binder/IInterface.h>
+
#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
+
#include <gui/OccupancyTracker.h>
#include <EGL/egl.h>
diff --git a/include/media/cas/CasAPI.h b/include/media/cas/CasAPI.h
new file mode 100644
index 0000000..0e88019
--- /dev/null
+++ b/include/media/cas/CasAPI.h
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+#ifndef CAS_API_H_
+#define CAS_API_H_
+
+#include <vector>
+#include <utils/String8.h>
+
+// Loadable CasPlugin shared libraries should define the entry points
+// as shown below:
+//
+// extern "C" {
+// extern android::CasFactory *createCasFactory();
+// extern android::DescramblerFactory *createDescramblerFactory();
+// }
+
+namespace android {
+
+struct CasPlugin;
+
+struct CasPluginDescriptor {
+ int32_t CA_system_id;
+ String8 name;
+};
+
+typedef std::vector<uint8_t> CasData;
+typedef std::vector<uint8_t> CasSessionId;
+typedef std::vector<uint8_t> CasEmm;
+typedef std::vector<uint8_t> CasEcm;
+typedef void (*CasPluginCallback)(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size);
+
+struct CasFactory {
+ CasFactory() {}
+ virtual ~CasFactory() {}
+
+ // Determine if the plugin can handle the CA scheme identified by CA_system_id.
+ virtual bool isSystemIdSupported(
+ int32_t CA_system_id) const = 0;
+
+ // Get a list of the CA schemes supported by the plugin.
+ virtual status_t queryPlugins(
+ std::vector<CasPluginDescriptor> *descriptors) const = 0;
+
+ // Construct a new instance of a CasPlugin given a CA_system_id
+ virtual status_t createPlugin(
+ int32_t CA_system_id,
+ uint64_t appData,
+ CasPluginCallback callback,
+ CasPlugin **plugin) = 0;
+
+private:
+ CasFactory(const CasFactory &);
+ CasFactory &operator=(const CasFactory &); /* NOLINT */
+};
+
+struct CasPlugin {
+ CasPlugin() {}
+ virtual ~CasPlugin() {}
+
+ // Provide the CA private data from a CA_descriptor in the conditional
+ // access table to a CasPlugin.
+ virtual status_t setPrivateData(
+ const CasData &privateData) = 0;
+
+ // Open a session for descrambling a program. The session will receive the
+ // ECM stream corresponding to the CA_PID for the program.
+ virtual status_t openSession(
+ uint16_t program_number,
+ CasSessionId *sessionId) = 0;
+
+ // Open a session for descrambling an elementary stream inside a program.
+ // The session will receive the ECM stream corresponding to the CA_PID for
+ // the stream.
+ virtual status_t openSession(
+ uint16_t program_number,
+ uint16_t elementary_PID,
+ CasSessionId *sessionId) = 0;
+
+ // Close a previously opened session.
+ virtual status_t closeSession(
+ const CasSessionId &sessionId) = 0;
+
+ // Provide the CA private data from a CA_descriptor in the program map
+ // table to a CasPlugin.
+ virtual status_t setSessionPrivateData(
+ const CasSessionId &sessionId,
+ const CasData &privateData) = 0;
+
+ // Process an ECM from the ECM stream for this session’s elementary stream.
+ virtual status_t processEcm(
+ const CasSessionId &sessionId,
+ const CasEcm &ecm) = 0;
+
+ // Process an in-band EMM from the EMM stream.
+ virtual status_t processEmm(
+ const CasEmm &emm) = 0;
+
+ // Deliver an event to the CasPlugin. The format of the event is specific
+ // to the CA scheme and is opaque to the framework.
+ virtual status_t sendEvent(
+ int32_t event,
+ int32_t arg,
+ const CasData &eventData) = 0;
+
+ // Native implementation of the MediaCas Java API provision method.
+ virtual status_t provision(
+ const String8 &provisionString) = 0;
+
+ // Native implementation of the MediaCas Java API refreshEntitlements method
+ virtual status_t refreshEntitlements(
+ int32_t refreshType,
+ const CasData &refreshData) = 0;
+
+private:
+ CasPlugin(const CasPlugin &);
+ CasPlugin &operator=(const CasPlugin &); /* NOLINT */
+};
+
+extern "C" {
+ extern android::CasFactory *createCasFactory();
+}
+
+} // namespace android
+
+#endif // CAS_API_H_
diff --git a/include/media/cas/DescramblerAPI.h b/include/media/cas/DescramblerAPI.h
new file mode 100644
index 0000000..0a51952
--- /dev/null
+++ b/include/media/cas/DescramblerAPI.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef DESCRAMBLER_API_H_
+#define DESCRAMBLER_API_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/cas/CasAPI.h>
+
+namespace android {
+
+struct AString;
+struct DescramblerPlugin;
+
+struct DescramblerFactory {
+ DescramblerFactory() {}
+ virtual ~DescramblerFactory() {}
+
+ // Determine if the plugin can handle the CA scheme identified by CA_system_id.
+ virtual bool isSystemIdSupported(
+ int32_t CA_system_id) const = 0;
+
+ // Construct a new instance of a DescramblerPlugin given a CA_system_id
+ virtual status_t createPlugin(
+ int32_t CA_system_id, DescramblerPlugin **plugin) = 0;
+
+private:
+ DescramblerFactory(const DescramblerFactory &);
+ DescramblerFactory &operator=(const DescramblerFactory &);
+};
+
+struct DescramblerPlugin {
+ enum ScramblingControl {
+ kScrambling_Unscrambled = 0,
+ kScrambling_Reserved = 1,
+ kScrambling_EvenKey = 2,
+ kScrambling_OddKey = 3,
+ };
+
+ struct SubSample {
+ uint32_t mNumBytesOfClearData;
+ uint32_t mNumBytesOfEncryptedData;
+ };
+
+ DescramblerPlugin() {}
+ virtual ~DescramblerPlugin() {}
+
+ // If this method returns false, a non-secure decoder will be used to
+ // decode the data after decryption. The decrypt API below will have
+ // to support insecure decryption of the data (secure = false) for
+ // media data of the given mime type.
+ virtual bool requiresSecureDecoderComponent(const char *mime) const = 0;
+
+ // A MediaCas session may be associated with a MediaCrypto session. The
+ // associated MediaCas session is used to load decryption keys
+ // into the crypto/cas plugin. The keys are then referenced by key-id
+ // in the 'key' parameter to the decrypt() method.
+ // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if
+ // the session is not opened and a code from MediaErrors.h otherwise.
+ virtual status_t setMediaCasSession(const CasSessionId& sessionId) = 0;
+
+ // If the error returned falls into the range
+ // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be
+ // filled in with an appropriate string.
+ // At the java level these special errors will then trigger a
+ // MediaCodec.CryptoException that gives clients access to both
+ // the error code and the errorDetailMsg.
+ // Returns a non-negative result to indicate the number of bytes written
+ // to the dstPtr, or a negative result to indicate an error.
+ virtual ssize_t descramble(
+ bool secure,
+ ScramblingControl scramblingControl,
+ size_t numSubSamples,
+ const SubSample *subSamples,
+ const void *srcPtr,
+ int32_t srcOffset,
+ void *dstPtr,
+ int32_t dstOffset,
+ AString *errorDetailMsg) = 0;
+
+private:
+ DescramblerPlugin(const DescramblerPlugin &);
+ DescramblerPlugin &operator=(const DescramblerPlugin &);
+};
+
+} // namespace android
+
+extern "C" {
+ extern android::DescramblerFactory *createDescramblerFactory();
+}
+
+#endif // DESCRAMBLER_API_H_
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index c7c3160..a22b2cb 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -27,10 +27,10 @@
class region_operator
{
public:
- typedef typename RECT::value_type TYPE;
- static const TYPE max_value = 0x7FFFFFF;
+ typedef typename RECT::value_type TYPE;
+ static const TYPE max_value = std::numeric_limits<TYPE>::max();
- /*
+ /*
* Common boolean operations:
* value is computed as 0b101 op 0b110
* other boolean operation are possible, simply compute
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 b1863df..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 {
@@ -212,14 +212,14 @@
return v;
}
- const std::string mName;
+ std::string mName;
- const mat3 mRGBtoXYZ;
- const mat3 mXYZtoRGB;
+ mat3 mRGBtoXYZ;
+ mat3 mXYZtoRGB;
- const transfer_function mOETF;
- const transfer_function mEOTF;
- const clamping_function mClamper;
+ transfer_function mOETF;
+ transfer_function mEOTF;
+ clamping_function mClamper;
std::array<float2, 3> mPrimaries;
float2 mWhitePoint;
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/Fence.h b/include/ui/Fence.h
index 58df24c..37811bc 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -23,8 +23,6 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include <experimental/optional>
-
namespace android {
class String8;
@@ -105,26 +103,29 @@
// error occurs then SIGNAL_TIME_INVALID is returned.
nsecs_t getSignalTime() const;
-#if __cplusplus > 201103L
- // hasSignaled returns whether the fence has signaled yet. Prefer this to
+ enum class Status {
+ Invalid, // Fence is invalid
+ Unsignaled, // Fence is valid but has not yet signaled
+ Signaled, // Fence is valid and has signaled
+ };
+
+ // getStatus() returns whether the fence has signaled yet. Prefer this to
// getSignalTime() or wait() if all you care about is whether the fence has
- // signaled. Returns an optional bool, which will have a value if there was
- // no error.
- inline std::experimental::optional<bool> hasSignaled() {
+ // signaled.
+ inline Status getStatus() {
// The sync_wait call underlying wait() has been measured to be
// significantly faster than the sync_fence_info call underlying
// getSignalTime(), which might otherwise appear to be the more obvious
// way to check whether a fence has signaled.
switch (wait(0)) {
case NO_ERROR:
- return true;
+ return Status::Signaled;
case -ETIME:
- return false;
+ return Status::Unsignaled;
default:
- return {};
+ return Status::Invalid;
}
}
-#endif
// Flattenable interface
size_t getFlattenedSize() const;
diff --git a/include/gfx/FloatRect.h b/include/ui/FloatRect.h
similarity index 96%
rename from include/gfx/FloatRect.h
rename to include/ui/FloatRect.h
index 6be5e22..270675c 100644
--- a/include/gfx/FloatRect.h
+++ b/include/ui/FloatRect.h
@@ -17,10 +17,9 @@
#pragma once
namespace android {
-namespace gfx {
class FloatRect {
- public:
+public:
FloatRect() = default;
constexpr FloatRect(float _left, float _top, float _right, float _bottom)
: left(_left), top(_top), right(_right), bottom(_bottom) {}
@@ -38,5 +37,4 @@
return a.left == b.left && a.top == b.top && a.right == b.right && a.bottom == b.bottom;
}
-} // namespace gfx
} // 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 fcd2245..6379a08 100644
--- a/include/ui/Gralloc1On0Adapter.h
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -17,9 +17,11 @@
#ifndef ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
#define ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
+#include <log/log.h>
+#include <ui/Fence.h>
+
+#include <hardware/gralloc.h>
#include <hardware/gralloc1.h>
#include <mutex>
@@ -27,35 +29,12 @@
#include <unordered_map>
#include <vector>
+namespace android {
+class GraphicBuffer;
+} // namespace android
+
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/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index ab7a9a3..02773d9 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -53,14 +53,15 @@
// real pixel formats supported for rendering -----------------------------
- PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
- PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
- PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
- PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
- PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
- PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB
- PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB
- PIXEL_FORMAT_RGBA_FP16 = HAL_PIXEL_FORMAT_RGBA_FP16, // 64-bit RGBA
+ PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
+ PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
+ PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
+ PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
+ PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
+ PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_FP16 = HAL_PIXEL_FORMAT_RGBA_FP16, // 64-bit RGBA
+ PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
};
typedef int32_t PixelFormat;
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index ce33d4e..b50e4ec 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -17,12 +17,12 @@
#ifndef ANDROID_UI_RECT
#define ANDROID_UI_RECT
-#include <gfx/FloatRect.h>
#include <utils/Flattenable.h>
#include <utils/Log.h>
#include <utils/TypeHelpers.h>
#include <log/log.h>
+#include <ui/FloatRect.h>
#include <ui/Point.h>
#include <android/rect.h>
@@ -45,13 +45,9 @@
template <typename T>
inline Rect(T w, T h) {
if (w > INT32_MAX) {
- ALOG(LOG_WARN, "Rect",
- "Width %u too large for Rect class, clamping", w);
w = INT32_MAX;
}
if (h > INT32_MAX) {
- ALOG(LOG_WARN, "Rect",
- "Height %u too large for Rect class, clamping", h);
h = INT32_MAX;
}
left = top = 0;
@@ -185,7 +181,7 @@
inline int32_t height() const { return getHeight(); }
inline void set(const Rect& rhs) { operator = (rhs); }
- gfx::FloatRect toFloatRect() const {
+ FloatRect toFloatRect() const {
return {static_cast<float>(left), static_cast<float>(top),
static_cast<float>(right), static_cast<float>(bottom)};
}
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
new file mode 100644
index 0000000..0d25176
--- /dev/null
+++ b/libs/arect/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+ndk_headers {
+ name: "libarect_headers",
+ from: "include/android",
+ to: "android",
+ srcs: ["include/android/*.h"],
+ license: "NOTICE",
+}
+
+cc_library_static {
+ name: "libarect",
+ host_supported: true,
+ export_include_dirs: ["include"],
+}
diff --git a/libs/arect/MODULE_LICENSE_APACHE2 b/libs/arect/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/arect/MODULE_LICENSE_APACHE2
diff --git a/libs/arect/NOTICE b/libs/arect/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/arect/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/android/rect.h b/libs/arect/include/android/rect.h
similarity index 100%
rename from include/android/rect.h
rename to libs/arect/include/android/rect.h
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ddf1072..8f9c38a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -107,6 +107,7 @@
"libGLESv2",
"libui",
"libutils",
+ "libnativewindow",
"liblog",
],
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index f76a282..13692eb 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -31,6 +31,13 @@
BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
+void BufferQueue::ProxyConsumerListener::onDisconnect() {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onDisconnect();
+ }
+}
+
void BufferQueue::ProxyConsumerListener::onFrameAvailable(
const BufferItem& item) {
sp<ConsumerListener> listener(mConsumerListener.promote());
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 3f69b1f..27ced61 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1222,6 +1222,9 @@
}
if (api == BufferQueueCore::CURRENTLY_CONNECTED_API) {
+ if (mCore->mConnectedApi == NATIVE_WINDOW_API_MEDIA) {
+ ALOGD("About to force-disconnect API_MEDIA, mode=%d", mode);
+ }
api = mCore->mConnectedApi;
// If we're asked to disconnect the currently connected api but
// nobody is connected, it's not really an error.
@@ -1272,6 +1275,7 @@
// Call back without lock held
if (listener != NULL) {
listener->onBuffersReleased();
+ listener->onDisconnect();
}
return status;
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index be2b1af..c26de66 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -318,16 +318,16 @@
return OK;
}
- auto signaled = mSlots[slot].mFence->hasSignaled();
+ auto status = mSlots[slot].mFence->getStatus();
- if (!signaled) {
+ if (status == Fence::Status::Invalid) {
CB_LOGE("fence has invalid state");
return BAD_VALUE;
}
- if (*signaled) {
+ if (status == Fence::Status::Signaled) {
mSlots[slot].mFence = fence;
- } else {
+ } else { // status == Fence::Status::Unsignaled
char fenceName[32] = {};
snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
sp<Fence> mergedFence = Fence::merge(
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index a9bafef..ae7c65c 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -65,6 +65,7 @@
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_BGRA_8888:
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a6fa38a..019a11e 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -16,6 +16,8 @@
#include <gui/FrameTimestamps.h>
+#define LOG_TAG "FrameEvents"
+
#include <cutils/compiler.h> // For CC_[UN]LIKELY
#include <inttypes.h>
#include <utils/Log.h>
@@ -33,19 +35,19 @@
// ============================================================================
bool FrameEvents::hasPostedInfo() const {
- return Fence::isValidTimestamp(postedTime);
+ return FrameEvents::isValidTimestamp(postedTime);
}
bool FrameEvents::hasRequestedPresentInfo() const {
- return Fence::isValidTimestamp(requestedPresentTime);
+ return FrameEvents::isValidTimestamp(requestedPresentTime);
}
bool FrameEvents::hasLatchInfo() const {
- return Fence::isValidTimestamp(latchTime);
+ return FrameEvents::isValidTimestamp(latchTime);
}
bool FrameEvents::hasFirstRefreshStartInfo() const {
- return Fence::isValidTimestamp(firstRefreshStartTime);
+ return FrameEvents::isValidTimestamp(firstRefreshStartTime);
}
bool FrameEvents::hasLastRefreshStartInfo() const {
@@ -56,7 +58,7 @@
}
bool FrameEvents::hasDequeueReadyInfo() const {
- return Fence::isValidTimestamp(dequeueReadyTime);
+ return FrameEvents::isValidTimestamp(dequeueReadyTime);
}
bool FrameEvents::hasAcquireInfo() const {
@@ -117,21 +119,21 @@
outString.appendFormat("--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
outString.appendFormat("--- Latched \t");
- if (Fence::isValidTimestamp(latchTime)) {
+ if (FrameEvents::isValidTimestamp(latchTime)) {
outString.appendFormat("%" PRId64 "\n", latchTime);
} else {
outString.appendFormat("Pending\n");
}
outString.appendFormat("--- Refresh (First)\t");
- if (Fence::isValidTimestamp(firstRefreshStartTime)) {
+ if (FrameEvents::isValidTimestamp(firstRefreshStartTime)) {
outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime);
} else {
outString.appendFormat("Pending\n");
}
outString.appendFormat("--- Refresh (Last)\t");
- if (Fence::isValidTimestamp(lastRefreshStartTime)) {
+ if (FrameEvents::isValidTimestamp(lastRefreshStartTime)) {
outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime);
} else {
outString.appendFormat("Pending\n");
@@ -147,7 +149,7 @@
!addRetireCalled, *displayRetireFence);
outString.appendFormat("--- DequeueReady \t");
- if (Fence::isValidTimestamp(dequeueReadyTime)) {
+ if (FrameEvents::isValidTimestamp(dequeueReadyTime)) {
outString.appendFormat("%" PRId64 "\n", dequeueReadyTime);
} else {
outString.appendFormat("Pending\n");
@@ -256,8 +258,7 @@
uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
if (frame == nullptr) {
- ALOGE("ProducerFrameEventHistory::updateAcquireFence: "
- "Did not find frame.");
+ ALOGE("updateAcquireFence: Did not find frame.");
return;
}
@@ -277,8 +278,8 @@
for (auto& d : delta.mDeltas) {
// Avoid out-of-bounds access.
- if (d.mIndex >= mFrames.size()) {
- ALOGE("ProducerFrameEventHistory::applyDelta: Bad index.");
+ if (CC_UNLIKELY(d.mIndex >= mFrames.size())) {
+ ALOGE("applyDelta: Bad index.");
return;
}
@@ -328,7 +329,7 @@
void ProducerFrameEventHistory::applyFenceDelta(FenceTimeline* timeline,
std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) const {
- if (CC_UNLIKELY(dst == nullptr)) {
+ if (CC_UNLIKELY(dst == nullptr || dst->get() == nullptr)) {
ALOGE("applyFenceDelta: dst is null.");
return;
}
@@ -337,9 +338,7 @@
case FenceTime::Snapshot::State::EMPTY:
return;
case FenceTime::Snapshot::State::FENCE:
- if (CC_UNLIKELY((*dst)->isValid())) {
- ALOGE("applyFenceDelta: Unexpected fence.");
- }
+ ALOGE_IF((*dst)->isValid(), "applyFenceDelta: Unexpected fence.");
*dst = createFenceTime(src.fence);
timeline->push(*dst);
return;
@@ -365,6 +364,11 @@
ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
+void ConsumerFrameEventHistory::onDisconnect() {
+ mCurrentConnectId++;
+ mProducerWantsEvents = false;
+}
+
void ConsumerFrameEventHistory::initializeCompositorTiming(
const CompositorTiming& compositorTiming) {
mCompositorTiming = compositorTiming;
@@ -373,6 +377,7 @@
void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
// Overwrite all fields of the frame with default values unless set here.
FrameEvents newTimestamps;
+ newTimestamps.connectId = mCurrentConnectId;
newTimestamps.frameNumber = newEntry.frameNumber;
newTimestamps.postedTime = newEntry.postedTime;
newTimestamps.requestedPresentTime = newEntry.requestedPresentTime;
@@ -409,7 +414,7 @@
}
frame->lastRefreshStartTime = refreshStartTime;
mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LAST_REFRESH_START>();
- if (!Fence::isValidTimestamp(frame->firstRefreshStartTime)) {
+ if (!FrameEvents::isValidTimestamp(frame->firstRefreshStartTime)) {
frame->firstRefreshStartTime = refreshStartTime;
mFramesDirty[mCompositionOffset].setDirty<FrameEvent::FIRST_REFRESH_START>();
}
@@ -431,7 +436,7 @@
if (!frame->addPostCompositeCalled) {
frame->addPostCompositeCalled = true;
frame->gpuCompositionDoneFence = gpuCompositionDone;
- mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GL_COMPOSITION_DONE>();
+ mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GPU_COMPOSITION_DONE>();
if (!frame->displayPresentFence->isValid()) {
frame->displayPresentFence = displayPresent;
mFramesDirty[mCompositionOffset].setDirty<FrameEvent::DISPLAY_PRESENT>();
@@ -455,7 +460,7 @@
nsecs_t dequeueReadyTime, std::shared_ptr<FenceTime>&& release) {
FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
if (frame == nullptr) {
- ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame.");
+ ALOGE_IF(mProducerWantsEvents, "addRelease: Did not find frame.");
return;
}
frame->addReleaseCalled = true;
@@ -470,13 +475,19 @@
mProducerWantsEvents = true;
size_t i = static_cast<size_t>(std::distance(mFrames.begin(), frame));
if (mFramesDirty[i].anyDirty()) {
- delta->mDeltas.emplace_back(i, *frame, mFramesDirty[i]);
+ // Make sure only to send back deltas for the current connection
+ // since the producer won't have the correct state to apply a delta
+ // from a previous connection.
+ if (mFrames[i].connectId == mCurrentConnectId) {
+ delta->mDeltas.emplace_back(i, *frame, mFramesDirty[i]);
+ }
mFramesDirty[i].reset();
}
}
void ConsumerFrameEventHistory::getAndResetDelta(
FrameEventHistoryDelta* delta) {
+ mProducerWantsEvents = true;
delta->mCompositorTiming = mCompositorTiming;
// Write these in order of frame number so that it is easy to
@@ -512,7 +523,7 @@
mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime),
mDequeueReadyTime(frameTimestamps.dequeueReadyTime) {
- if (dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>()) {
+ if (dirtyFields.isDirty<FrameEvent::GPU_COMPOSITION_DONE>()) {
mGpuCompositionDoneFence =
frameTimestamps.gpuCompositionDoneFence->getSnapshot();
}
@@ -648,7 +659,7 @@
mCompositorTiming = src.mCompositorTiming;
if (CC_UNLIKELY(!mDeltas.empty())) {
- ALOGE("FrameEventHistoryDelta: Clobbering history.");
+ ALOGE("FrameEventHistoryDelta assign clobbering history.");
}
mDeltas = std::move(src.mDeltas);
ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty.");
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 9532c52..55e0d26 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -863,6 +863,7 @@
case PIXEL_FORMAT_RGBA_8888:
case PIXEL_FORMAT_RGBX_8888:
case PIXEL_FORMAT_RGBA_FP16:
+ case PIXEL_FORMAT_RGBA_1010102:
case PIXEL_FORMAT_RGB_888:
case PIXEL_FORMAT_RGB_565:
case PIXEL_FORMAT_BGRA_8888:
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 3d893b1..8cadc4d 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,8 @@
// ---------------------------------------------------------------------------
enum {
- ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
+ ON_DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ ON_FRAME_AVAILABLE,
ON_BUFFER_RELEASED,
ON_SIDEBAND_STREAM_CHANGED,
GET_FRAME_TIMESTAMPS
@@ -43,6 +44,12 @@
virtual ~BpConsumerListener();
+ virtual void onDisconnect() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+ remote()->transact(ON_DISCONNECT, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
virtual void onFrameAvailable(const BufferItem& item) {
Parcel data, reply;
data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
@@ -75,6 +82,10 @@
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
+ case ON_DISCONNECT: {
+ CHECK_INTERFACE(IConsumerListener, data, reply);
+ onDisconnect();
+ return NO_ERROR; }
case ON_FRAME_AVAILABLE: {
CHECK_INTERFACE(IConsumerListener, data, reply);
BufferItem item;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d285ef0..efb1524 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -196,7 +196,7 @@
const nsecs_t* outLatchTime,
const nsecs_t* outFirstRefreshStartTime,
const nsecs_t* outLastRefreshStartTime,
- const nsecs_t* outGlCompositionDoneTime,
+ const nsecs_t* outGpuCompositionDoneTime,
const nsecs_t* outDisplayPresentTime,
const nsecs_t* outDisplayRetireTime,
const nsecs_t* outDequeueReadyTime,
@@ -204,7 +204,7 @@
bool checkForLatch = (outLatchTime != nullptr) && !e->hasLatchInfo();
bool checkForFirstRefreshStart = (outFirstRefreshStartTime != nullptr) &&
!e->hasFirstRefreshStartInfo();
- bool checkForGlCompositionDone = (outGlCompositionDoneTime != nullptr) &&
+ bool checkForGpuCompositionDone = (outGpuCompositionDoneTime != nullptr) &&
!e->hasGpuCompositionDoneInfo();
bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
!e->hasDisplayPresentInfo();
@@ -223,14 +223,14 @@
// RequestedPresent and Acquire info are always available producer-side.
return checkForLatch || checkForFirstRefreshStart ||
- checkForLastRefreshStart || checkForGlCompositionDone ||
+ checkForLastRefreshStart || checkForGpuCompositionDone ||
checkForDisplayPresent || checkForDisplayRetire ||
checkForDequeueReady || checkForRelease;
}
static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
if (dst != nullptr) {
- *dst = Fence::isValidTimestamp(src) ? src : 0;
+ *dst = FrameEvents::isValidTimestamp(src) ? src : 0;
}
}
@@ -244,7 +244,7 @@
status_t Surface::getFrameTimestamps(uint64_t frameNumber,
nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
- nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+ nsecs_t* outLastRefreshStartTime, nsecs_t* outGpuCompositionDoneTime,
nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime) {
ATRACE_CALL();
@@ -274,7 +274,7 @@
// Update our cache of events if the requested events are not available.
if (checkConsumerForUpdates(events, mLastFrameNumber,
outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
- outGlCompositionDoneTime, outDisplayPresentTime,
+ outGpuCompositionDoneTime, outDisplayPresentTime,
outDisplayRetireTime, outDequeueReadyTime, outReleaseTime)) {
FrameEventHistoryDelta delta;
mGraphicBufferProducer->getFrameTimestamps(&delta);
@@ -296,7 +296,7 @@
getFrameTimestampFence(outAcquireTime, events->acquireFence);
getFrameTimestampFence(
- outGlCompositionDoneTime, events->gpuCompositionDoneFence);
+ outGpuCompositionDoneTime, events->gpuCompositionDoneFence);
getFrameTimestampFence(
outDisplayPresentTime, events->displayPresentFence);
getFrameTimestampFence(outDisplayRetireTime, events->displayRetireFence);
@@ -1032,7 +1032,7 @@
nsecs_t* outLatchTime = va_arg(args, int64_t*);
nsecs_t* outFirstRefreshStartTime = va_arg(args, int64_t*);
nsecs_t* outLastRefreshStartTime = va_arg(args, int64_t*);
- nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
+ nsecs_t* outGpuCompositionDoneTime = va_arg(args, int64_t*);
nsecs_t* outDisplayPresentTime = va_arg(args, int64_t*);
nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
@@ -1040,7 +1040,7 @@
return getFrameTimestamps(frameId,
outRequestedPresentTime, outAcquireTime, outLatchTime,
outFirstRefreshStartTime, outLastRefreshStartTime,
- outGlCompositionDoneTime, outDisplayPresentTime,
+ outGpuCompositionDoneTime, outDisplayPresentTime,
outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
}
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 092d597..5944110 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -15,7 +15,6 @@
"IGraphicBufferProducer_test.cpp",
"MultiTextureConsumer_test.cpp",
"Sensor_test.cpp",
- "SRGB_test.cpp",
"StreamSplitter_test.cpp",
"SurfaceTextureClient_test.cpp",
"SurfaceTextureFBO_test.cpp",
@@ -37,5 +36,6 @@
"libgui",
"libui",
"libutils",
+ "libnativewindow"
],
}
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h
index 0511e16..502bdf9 100644
--- a/libs/gui/tests/DummyConsumer.h
+++ b/libs/gui/tests/DummyConsumer.h
@@ -19,9 +19,9 @@
namespace android {
struct DummyConsumer : public BnConsumerListener {
- virtual void onFrameAvailable(const BufferItem& /* item */) {}
- virtual void onBuffersReleased() {}
- virtual void onSidebandStreamChanged() {}
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
};
} // namespace android
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 0329a6d..aa071f6 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "IGraphicBufferProducer_test"
//#define LOG_NDEBUG 0
+#include "DummyConsumer.h"
+
#include <gtest/gtest.h>
#include <utils/String8.h>
@@ -64,12 +66,6 @@
const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
}; // namespace anonymous
-struct DummyConsumer : public BnConsumerListener {
- virtual void onFrameAvailable(const BufferItem& /* item */) {}
- virtual void onBuffersReleased() {}
- virtual void onSidebandStreamChanged() {}
-};
-
class IGraphicBufferProducerTest : public ::testing::Test {
protected:
diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp
deleted file mode 100644
index c2640cd..0000000
--- a/libs/gui/tests/SRGB_test.cpp
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SRGB_test"
-//#define LOG_NDEBUG 0
-
-// Ignore for this file because it flags every instance of
-// ASSERT_EQ(GL_NO_ERROR, glGetError());
-#pragma clang diagnostic ignored "-Wsign-compare"
-
-#include "GLTest.h"
-
-#include <math.h>
-
-#include <gui/CpuConsumer.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES3/gl3.h>
-
-#include <android/native_window.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-class SRGBTest : public ::testing::Test {
-protected:
- // Class constants
- enum {
- DISPLAY_WIDTH = 512,
- DISPLAY_HEIGHT = 512,
- PIXEL_SIZE = 4, // bytes or components
- DISPLAY_SIZE = DISPLAY_WIDTH * DISPLAY_HEIGHT * PIXEL_SIZE,
- ALPHA_VALUE = 223, // should be in [0, 255]
- TOLERANCE = 1,
- };
- static const char SHOW_DEBUG_STRING[];
-
- SRGBTest() :
- mInputSurface(), mCpuConsumer(), mLockedBuffer(),
- mEglDisplay(EGL_NO_DISPLAY), mEglConfig(),
- mEglContext(EGL_NO_CONTEXT), mEglSurface(EGL_NO_SURFACE),
- mComposerClient(), mSurfaceControl(), mOutputSurface() {
- }
-
- virtual ~SRGBTest() {
- if (mEglDisplay != EGL_NO_DISPLAY) {
- if (mEglSurface != EGL_NO_SURFACE) {
- eglDestroySurface(mEglDisplay, mEglSurface);
- }
- if (mEglContext != EGL_NO_CONTEXT) {
- eglDestroyContext(mEglDisplay, mEglContext);
- }
- eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
- eglTerminate(mEglDisplay);
- }
- }
-
- virtual void SetUp() {
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- ASSERT_EQ(NO_ERROR, consumer->setDefaultBufferSize(
- DISPLAY_WIDTH, DISPLAY_HEIGHT));
- mCpuConsumer = new CpuConsumer(consumer, 1);
- String8 name("CpuConsumer_for_SRGBTest");
- mCpuConsumer->setName(name);
- mInputSurface = new Surface(producer);
-
- ASSERT_NO_FATAL_FAILURE(createEGLSurface(mInputSurface.get()));
- ASSERT_NO_FATAL_FAILURE(createDebugSurface());
- }
-
- virtual void TearDown() {
- ASSERT_NO_FATAL_FAILURE(copyToDebugSurface());
- ASSERT_TRUE(mLockedBuffer.data != NULL);
- ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
- }
-
- static float linearToSRGB(float l) {
- if (l <= 0.0031308f) {
- return l * 12.92f;
- } else {
- return 1.055f * pow(l, (1 / 2.4f)) - 0.055f;
- }
- }
-
- static float srgbToLinear(float s) {
- if (s <= 0.04045) {
- return s / 12.92f;
- } else {
- return pow(((s + 0.055f) / 1.055f), 2.4f);
- }
- }
-
- static uint8_t srgbToLinear(uint8_t u) {
- float f = u / 255.0f;
- return static_cast<uint8_t>(srgbToLinear(f) * 255.0f + 0.5f);
- }
-
- void fillTexture(bool writeAsSRGB) {
- uint8_t* textureData = new uint8_t[DISPLAY_SIZE];
-
- for (int y = 0; y < DISPLAY_HEIGHT; ++y) {
- for (int x = 0; x < DISPLAY_WIDTH; ++x) {
- float realValue = static_cast<float>(x) / (DISPLAY_WIDTH - 1);
- realValue *= ALPHA_VALUE / 255.0f; // Premultiply by alpha
- if (writeAsSRGB) {
- realValue = linearToSRGB(realValue);
- }
-
- int offset = (y * DISPLAY_WIDTH + x) * PIXEL_SIZE;
- for (int c = 0; c < 3; ++c) {
- uint8_t intValue = static_cast<uint8_t>(
- realValue * 255.0f + 0.5f);
- textureData[offset + c] = intValue;
- }
- textureData[offset + 3] = ALPHA_VALUE;
- }
- }
-
- glTexImage2D(GL_TEXTURE_2D, 0, writeAsSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- textureData);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
-
- delete[] textureData;
- }
-
- void initShaders() {
- static const char vertexSource[] =
- "attribute vec4 vPosition;\n"
- "varying vec2 texCoords;\n"
- "void main() {\n"
- " texCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
- " gl_Position = vPosition;\n"
- "}\n";
-
- static const char fragmentSource[] =
- "precision mediump float;\n"
- "uniform sampler2D texSampler;\n"
- "varying vec2 texCoords;\n"
- "void main() {\n"
- " gl_FragColor = texture2D(texSampler, texCoords);\n"
- "}\n";
-
- GLuint program;
- {
- SCOPED_TRACE("Creating shader program");
- ASSERT_NO_FATAL_FAILURE(GLTest::createProgram(
- vertexSource, fragmentSource, &program));
- }
-
- GLint positionHandle = glGetAttribLocation(program, "vPosition");
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- ASSERT_NE(-1, positionHandle);
-
- GLint samplerHandle = glGetUniformLocation(program, "texSampler");
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- ASSERT_NE(-1, samplerHandle);
-
- static const GLfloat vertices[] = {
- -1.0f, 1.0f,
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 1.0f, 1.0f,
- };
-
- glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glEnableVertexAttribArray(positionHandle);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
-
- glUseProgram(program);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glUniform1i(samplerHandle, 0);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
-
- GLuint textureHandle;
- glGenTextures(1, &textureHandle);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glBindTexture(GL_TEXTURE_2D, textureHandle);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- }
-
- void drawTexture(bool asSRGB, GLint x, GLint y, GLsizei width,
- GLsizei height) {
- ASSERT_NO_FATAL_FAILURE(fillTexture(asSRGB));
- glViewport(x, y, width, height);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- ASSERT_EQ(GL_NO_ERROR, glGetError());
- }
-
- void checkLockedBuffer(PixelFormat format, android_dataspace dataSpace) {
- ASSERT_EQ(mLockedBuffer.format, format);
- ASSERT_EQ(mLockedBuffer.width, DISPLAY_WIDTH);
- ASSERT_EQ(mLockedBuffer.height, DISPLAY_HEIGHT);
- ASSERT_EQ(mLockedBuffer.dataSpace, dataSpace);
- }
-
- static bool withinTolerance(int a, int b) {
- int diff = a - b;
- return diff >= 0 ? diff <= TOLERANCE : -diff <= TOLERANCE;
- }
-
- // Primary producer and consumer
- sp<Surface> mInputSurface;
- sp<CpuConsumer> mCpuConsumer;
- CpuConsumer::LockedBuffer mLockedBuffer;
-
- EGLDisplay mEglDisplay;
- EGLConfig mEglConfig;
- EGLContext mEglContext;
- EGLSurface mEglSurface;
-
- // Auxiliary display output
- sp<SurfaceComposerClient> mComposerClient;
- sp<SurfaceControl> mSurfaceControl;
- sp<Surface> mOutputSurface;
-
-private:
- void createEGLSurface(Surface* inputSurface) {
- mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
-
- EXPECT_TRUE(eglInitialize(mEglDisplay, NULL, NULL));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- static const EGLint configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_NONE };
-
- EGLint numConfigs = 0;
- EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &mEglConfig, 1,
- &numConfigs));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_GT(numConfigs, 0);
-
- static const EGLint contextAttribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 3,
- EGL_NONE } ;
-
- mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
- contextAttribs);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
-
- mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
- inputSurface, NULL);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
-
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
- mEglContext));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- }
-
- void createDebugSurface() {
- if (getenv(SHOW_DEBUG_STRING) == NULL) return;
-
- mComposerClient = new SurfaceComposerClient;
- ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- mSurfaceControl = mComposerClient->createSurface(
- String8("SRGBTest Surface"), DISPLAY_WIDTH, DISPLAY_HEIGHT,
- PIXEL_FORMAT_RGBA_8888);
-
- ASSERT_TRUE(mSurfaceControl != NULL);
- ASSERT_TRUE(mSurfaceControl->isValid());
-
- SurfaceComposerClient::openGlobalTransaction();
- ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
- ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- SurfaceComposerClient::closeGlobalTransaction();
-
- ANativeWindow_Buffer outBuffer;
- ARect inOutDirtyBounds;
- mOutputSurface = mSurfaceControl->getSurface();
- mOutputSurface->lock(&outBuffer, &inOutDirtyBounds);
- uint8_t* bytePointer = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; ++y) {
- int rowOffset = y * outBuffer.stride; // pixels
- for (int x = 0; x < outBuffer.width; ++x) {
- int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes
- for (int c = 0; c < PIXEL_SIZE; ++c) {
- int offset = colOffset + c;
- bytePointer[offset] = ((c + 1) * 56) - 1;
- }
- }
- }
- mOutputSurface->unlockAndPost();
- }
-
- void copyToDebugSurface() {
- if (!mOutputSurface.get()) return;
-
- size_t bufferSize = mLockedBuffer.height * mLockedBuffer.stride *
- PIXEL_SIZE;
-
- ANativeWindow_Buffer outBuffer;
- ARect outBufferBounds;
- mOutputSurface->lock(&outBuffer, &outBufferBounds);
- ASSERT_EQ(mLockedBuffer.width, static_cast<uint32_t>(outBuffer.width));
- ASSERT_EQ(mLockedBuffer.height, static_cast<uint32_t>(outBuffer.height));
- ASSERT_EQ(mLockedBuffer.stride, static_cast<uint32_t>(outBuffer.stride));
-
- if (mLockedBuffer.format == outBuffer.format) {
- memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize);
- } else {
- ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_RGBA_8888);
- ASSERT_EQ(mLockedBuffer.dataSpace, HAL_DATASPACE_SRGB);
- ASSERT_EQ(outBuffer.format, PIXEL_FORMAT_RGBA_8888);
- uint8_t* outPointer = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; ++y) {
- int rowOffset = y * outBuffer.stride; // pixels
- for (int x = 0; x < outBuffer.width; ++x) {
- int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes
-
- // RGB are converted
- for (int c = 0; c < (PIXEL_SIZE - 1); ++c) {
- outPointer[colOffset + c] = srgbToLinear(
- mLockedBuffer.data[colOffset + c]);
- }
-
- // Alpha isn't converted
- outPointer[colOffset + 3] =
- mLockedBuffer.data[colOffset + 3];
- }
- }
- }
- mOutputSurface->unlockAndPost();
-
- int sleepSeconds = atoi(getenv(SHOW_DEBUG_STRING));
- sleep(sleepSeconds);
- }
-};
-
-const char SRGBTest::SHOW_DEBUG_STRING[] = "DEBUG_OUTPUT_SECONDS";
-
-TEST_F(SRGBTest, GLRenderFromSRGBTexture) {
- ASSERT_NO_FATAL_FAILURE(initShaders());
-
- // The RGB texture is displayed in the top half
- ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, DISPLAY_HEIGHT / 2,
- DISPLAY_WIDTH, DISPLAY_HEIGHT / 2));
-
- // The SRGB texture is displayed in the bottom half
- ASSERT_NO_FATAL_FAILURE(drawTexture(true, 0, 0,
- DISPLAY_WIDTH, DISPLAY_HEIGHT / 2));
-
- eglSwapBuffers(mEglDisplay, mEglSurface);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- // Lock
- ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
- ASSERT_NO_FATAL_FAILURE(
- checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN));
-
- // Compare a pixel in the middle of each texture
- int midSRGBOffset = (DISPLAY_HEIGHT / 4) * mLockedBuffer.stride *
- PIXEL_SIZE;
- int midRGBOffset = midSRGBOffset * 3;
- midRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
- midSRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
- for (int c = 0; c < PIXEL_SIZE; ++c) {
- int expectedValue = mLockedBuffer.data[midRGBOffset + c];
- int actualValue = mLockedBuffer.data[midSRGBOffset + c];
- ASSERT_PRED2(withinTolerance, expectedValue, actualValue);
- }
-
- // mLockedBuffer is unlocked in TearDown so we can copy data from it to
- // the debug surface if necessary
-}
-
-// XXX: Disabled since we don't currently expect this to work
-TEST_F(SRGBTest, DISABLED_RenderToSRGBSurface) {
- ASSERT_NO_FATAL_FAILURE(initShaders());
-
- // By default, the first buffer we write into will be RGB
-
- // Render an RGB texture across the whole surface
- ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0,
- DISPLAY_WIDTH, DISPLAY_HEIGHT));
- eglSwapBuffers(mEglDisplay, mEglSurface);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- // Lock
- ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
- ASSERT_NO_FATAL_FAILURE(
- checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN));
-
- // Save the values of the middle pixel for later comparison against SRGB
- uint8_t values[PIXEL_SIZE] = {};
- int middleOffset = (DISPLAY_HEIGHT / 2) * mLockedBuffer.stride *
- PIXEL_SIZE;
- middleOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
- for (int c = 0; c < PIXEL_SIZE; ++c) {
- values[c] = mLockedBuffer.data[middleOffset + c];
- }
-
- // Unlock
- ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
-
- // Switch to SRGB window surface
- static const int srgbAttribs[] = {
- EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
- EGL_NONE,
- };
-
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
- mEglContext));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
- mInputSurface.get(), srgbAttribs);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
-
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
- mEglContext));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- // Render the texture again
- ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0,
- DISPLAY_WIDTH, DISPLAY_HEIGHT));
- eglSwapBuffers(mEglDisplay, mEglSurface);
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- // Lock
- ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
-
- // Make sure we actually got the SRGB buffer on the consumer side
- ASSERT_NO_FATAL_FAILURE(
- checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_SRGB));
-
- // Verify that the stored value is the same, accounting for RGB/SRGB
- for (int c = 0; c < PIXEL_SIZE; ++c) {
- // The alpha value should be equivalent before linear->SRGB
- float rgbAsSRGB = (c == 3) ? values[c] / 255.0f :
- linearToSRGB(values[c] / 255.0f);
- int expectedValue = rgbAsSRGB * 255.0f + 0.5f;
- int actualValue = mLockedBuffer.data[middleOffset + c];
- ASSERT_PRED2(withinTolerance, expectedValue, actualValue);
- }
-
- // mLockedBuffer is unlocked in TearDown so we can copy data from it to
- // the debug surface if necessary
-}
-
-} // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index b10d4eb..bd598e4 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
+#include <gui/BufferQueue.h>
#include <system/graphics.h>
#include <utils/Log.h>
#include <utils/Thread.h>
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 5298027..ceeb90a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -364,7 +364,7 @@
FrameEvent::LATCH,
FrameEvent::FIRST_REFRESH_START,
FrameEvent::LAST_REFRESH_START,
- FrameEvent::GL_COMPOSITION_DONE,
+ FrameEvent::GPU_COMPOSITION_DONE,
FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE
};
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/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
new file mode 100644
index 0000000..b4b5303
--- /dev/null
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHardwareBuffer"
+
+#include <android/hardware_buffer.h>
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <memory>
+
+#include <cutils/native_handle.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include <ui/GraphicBuffer.h>
+#include <system/graphics.h>
+#include <hardware/gralloc1.h>
+
+#include <private/android/AHardwareBufferHelpers.h>
+
+
+static constexpr int kDataBufferSize = 64 * sizeof(int); // 64 ints
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Public functions
+// ----------------------------------------------------------------------------
+
+int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer) {
+ if (!outBuffer || !desc)
+ return BAD_VALUE;
+
+ int format = AHardwareBuffer_convertToPixelFormat(desc->format);
+ if (format == 0) {
+ ALOGE("Invalid pixel format %u", desc->format);
+ return BAD_VALUE;
+ }
+
+ if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) {
+ ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB format");
+ return BAD_VALUE;
+ }
+
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
+ AHardwareBuffer_convertToGrallocUsageBits(desc->usage0, &producerUsage, &consumerUsage);
+
+ sp<GraphicBuffer> gbuffer(new GraphicBuffer(
+ desc->width, desc->height, format, desc->layers, producerUsage, consumerUsage,
+ std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]"));
+
+ status_t err = gbuffer->initCheck();
+ if (err != 0 || gbuffer->handle == 0) {
+ if (err == NO_MEMORY) {
+ GraphicBuffer::dumpAllocationsToSystemLog();
+ }
+ ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
+ desc->width, desc->height, desc->layers, strerror(-err), gbuffer->handle);
+ return err;
+ }
+
+ *outBuffer = AHardwareBuffer_from_GraphicBuffer(gbuffer.get());
+
+ // Ensure the buffer doesn't get destroyed when the sp<> goes away.
+ AHardwareBuffer_acquire(*outBuffer);
+ return NO_ERROR;
+}
+
+void AHardwareBuffer_acquire(AHardwareBuffer* buffer) {
+ AHardwareBuffer_to_GraphicBuffer(buffer)->incStrong((void*)AHardwareBuffer_acquire);
+}
+
+void AHardwareBuffer_release(AHardwareBuffer* buffer) {
+ AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong((void*)AHardwareBuffer_release);
+}
+
+void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
+ AHardwareBuffer_Desc* outDesc) {
+ if (!buffer || !outDesc) return;
+
+ const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+ outDesc->width = gbuffer->getWidth();
+ outDesc->height = gbuffer->getHeight();
+ outDesc->layers = gbuffer->getLayerCount();
+ outDesc->usage0 = AHardwareBuffer_convertFromGrallocUsageBits(
+ gbuffer->getUsage(), gbuffer->getUsage());
+ outDesc->usage1 = 0;
+ outDesc->format = AHardwareBuffer_convertFromPixelFormat(
+ static_cast<uint32_t>(gbuffer->getPixelFormat()));
+}
+
+int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage0,
+ int32_t fence, const ARect* rect, void** outVirtualAddress) {
+ if (!buffer) return BAD_VALUE;
+
+ if (usage0 & ~(AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN)) {
+ ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+ " AHARDWAREBUFFER_USAGE0_CPU_* flags are allowed");
+ return BAD_VALUE;
+ }
+
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
+ AHardwareBuffer_convertToGrallocUsageBits(usage0, &producerUsage, &consumerUsage);
+ GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+ Rect bounds;
+ if (!rect) {
+ bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
+ } else {
+ bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
+ }
+ return gBuffer->lockAsync(producerUsage, consumerUsage, bounds,
+ outVirtualAddress, fence);
+}
+
+int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
+ if (!buffer) return BAD_VALUE;
+
+ GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+ return gBuffer->unlockAsync(fence);
+}
+
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
+ int socketFd) {
+ if (!buffer) return BAD_VALUE;
+ const GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+ size_t flattenedSize = gBuffer->getFlattenedSize();
+ size_t fdCount = gBuffer->getFdCount();
+
+ std::unique_ptr<uint8_t[]> data(new uint8_t[flattenedSize]);
+ std::unique_ptr<int[]> fds(new int[fdCount]);
+
+ // Make copies of needed items since flatten modifies them, and we don't
+ // want to send anything if there's an error during flatten.
+ size_t flattenedSizeCopy = flattenedSize;
+ size_t fdCountCopy = fdCount;
+ void* dataStart = data.get();
+ int* fdsStart = fds.get();
+ status_t err = gBuffer->flatten(dataStart, flattenedSizeCopy, fdsStart,
+ fdCountCopy);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ struct iovec iov[1];
+ iov[0].iov_base = data.get();
+ iov[0].iov_len = flattenedSize;
+
+ char buf[CMSG_SPACE(kDataBufferSize)];
+ struct msghdr msg = {
+ .msg_control = buf,
+ .msg_controllen = sizeof(buf),
+ .msg_iov = &iov[0],
+ .msg_iovlen = 1,
+ };
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount);
+ int* fdData = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ memcpy(fdData, fds.get(), sizeof(int) * fdCount);
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ int result = sendmsg(socketFd, &msg, 0);
+ if (result <= 0) {
+ ALOGE("Error writing AHardwareBuffer to socket: error %#x (%s)",
+ result, strerror(errno));
+ return result;
+ }
+ return NO_ERROR;
+}
+
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
+ AHardwareBuffer** outBuffer) {
+ if (!outBuffer) return BAD_VALUE;
+
+ char dataBuf[CMSG_SPACE(kDataBufferSize)];
+ char fdBuf[CMSG_SPACE(kDataBufferSize)];
+ struct iovec iov[1];
+ iov[0].iov_base = dataBuf;
+ iov[0].iov_len = sizeof(dataBuf);
+
+ struct msghdr msg = {
+ .msg_control = fdBuf,
+ .msg_controllen = sizeof(fdBuf),
+ .msg_iov = &iov[0],
+ .msg_iovlen = 1,
+ };
+
+ int result = recvmsg(socketFd, &msg, 0);
+ if (result <= 0) {
+ ALOGE("Error reading AHardwareBuffer from socket: error %#x (%s)",
+ result, strerror(errno));
+ return result;
+ }
+
+ if (msg.msg_iovlen != 1) {
+ ALOGE("Error reading AHardwareBuffer from socket: bad data length");
+ return INVALID_OPERATION;
+ }
+
+ if (msg.msg_controllen % sizeof(int) != 0) {
+ ALOGE("Error reading AHardwareBuffer from socket: bad fd length");
+ return INVALID_OPERATION;
+ }
+
+ size_t dataLen = msg.msg_iov[0].iov_len;
+ const void* data = static_cast<const void*>(msg.msg_iov[0].iov_base);
+ if (!data) {
+ ALOGE("Error reading AHardwareBuffer from socket: no buffer data");
+ return INVALID_OPERATION;
+ }
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg) {
+ ALOGE("Error reading AHardwareBuffer from socket: no fd header");
+ return INVALID_OPERATION;
+ }
+
+ size_t fdCount = msg.msg_controllen >> 2;
+ const int* fdData = reinterpret_cast<const int*>(CMSG_DATA(cmsg));
+ if (!fdData) {
+ ALOGE("Error reading AHardwareBuffer from socket: no fd data");
+ return INVALID_OPERATION;
+ }
+
+ GraphicBuffer* gBuffer = new GraphicBuffer();
+ status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer);
+ // Ensure the buffer has a positive ref-count.
+ AHardwareBuffer_acquire(*outBuffer);
+
+ return NO_ERROR;
+}
+
+const struct native_handle* AHardwareBuffer_getNativeHandle(
+ const AHardwareBuffer* buffer) {
+ if (!buffer) return nullptr;
+ const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+ return gbuffer->handle;
+}
+
+
+// ----------------------------------------------------------------------------
+// Helpers implementation
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
+ return (mask & bitsToCheck) == bitsToCheck;
+}
+
+uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888: return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+ case HAL_PIXEL_FORMAT_RGBX_8888: return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+ case HAL_PIXEL_FORMAT_RGB_565: return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+ case HAL_PIXEL_FORMAT_RGB_888: return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+ case HAL_PIXEL_FORMAT_RGBA_FP16: return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT;
+ case HAL_PIXEL_FORMAT_RGBA_1010102: return AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32;
+ case HAL_PIXEL_FORMAT_BLOB: return AHARDWAREBUFFER_FORMAT_BLOB;
+ default:ALOGE("Unknown pixel format %u", format);
+ return 0;
+ }
+}
+
+uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format) {
+ switch (format) {
+ case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: return HAL_PIXEL_FORMAT_RGBA_8888;
+ case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: return HAL_PIXEL_FORMAT_RGBX_8888;
+ case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: return HAL_PIXEL_FORMAT_RGB_565;
+ case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: return HAL_PIXEL_FORMAT_RGB_888;
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT: return HAL_PIXEL_FORMAT_RGBA_FP16;
+ case AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32: return HAL_PIXEL_FORMAT_RGBA_1010102;
+ case AHARDWAREBUFFER_FORMAT_BLOB: return HAL_PIXEL_FORMAT_BLOB;
+ default:ALOGE("Unknown AHardwareBuffer format %u", format);
+ return 0;
+ }
+}
+
+void AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage, uint64_t* outProducerUsage,
+ uint64_t* outConsumerUsage) {
+ *outProducerUsage = 0;
+ *outConsumerUsage = 0;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_CPU_READ))
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN))
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_CPU_WRITE))
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN))
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE))
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT))
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
+ // Not sure what this should be.
+ //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER))
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE))
+ *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT))
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
+ if (containsBits(usage, AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA))
+ *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
+}
+
+uint64_t AHardwareBuffer_convertFromGrallocUsageBits(uint64_t producerUsage, uint64_t consumerUsage) {
+ uint64_t bits = 0;
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ))
+ bits |= AHARDWAREBUFFER_USAGE0_CPU_READ;
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN))
+ bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE))
+ bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE;
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN))
+ bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN;
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE))
+ bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET))
+ bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT;
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER))
+ bits |= AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER;
+ if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER))
+ bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE;
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_PROTECTED))
+ bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT;
+ if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA))
+ bits |= AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA;
+
+ return bits;
+}
+
+const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer) {
+ return reinterpret_cast<const GraphicBuffer*>(buffer);
+}
+
+GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer) {
+ return reinterpret_cast<GraphicBuffer*>(buffer);
+}
+
+AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
+ return reinterpret_cast<AHardwareBuffer*>(buffer);
+}
+
+} // namespace android
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
new file mode 100644
index 0000000..34c136a
--- /dev/null
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ANativeWindow"
+
+#include <android/native_window.h>
+#include <system/window.h>
+
+void ANativeWindow_acquire(ANativeWindow* window) {
+ window->incStrong((void*)ANativeWindow_acquire);
+}
+
+void ANativeWindow_release(ANativeWindow* window) {
+ window->decStrong((void*)ANativeWindow_release);
+}
+
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+ int value;
+ int res = window->query(window, what, &value);
+ return res < 0 ? res : value;
+}
+
+int32_t ANativeWindow_getWidth(ANativeWindow* window) {
+ return getWindowProp(window, NATIVE_WINDOW_WIDTH);
+}
+
+int32_t ANativeWindow_getHeight(ANativeWindow* window) {
+ return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
+}
+
+int32_t ANativeWindow_getFormat(ANativeWindow* window) {
+ return getWindowProp(window, NATIVE_WINDOW_FORMAT);
+}
+
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
+ int32_t height, int32_t format) {
+ int32_t err = native_window_set_buffers_format(window, format);
+ if (!err) {
+ err = native_window_set_buffers_user_dimensions(window, width, height);
+ if (!err) {
+ int mode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ if (width && height) {
+ mode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+ }
+ err = native_window_set_scaling_mode(window, mode);
+ }
+ }
+ return err;
+}
+
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+ ARect* inOutDirtyBounds) {
+ return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
+}
+
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
+ return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
+}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
new file mode 100644
index 0000000..46e5d50
--- /dev/null
+++ b/libs/nativewindow/Android.bp
@@ -0,0 +1,50 @@
+// 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.
+
+ndk_headers {
+ name: "libnativewindwow_headers",
+ from: "include/android",
+ to: "android",
+ srcs: ["include/android/*.h"],
+ license: "NOTICE",
+}
+
+cc_library {
+ name: "libnativewindow",
+ export_include_dirs: ["include"],
+
+ clang: true,
+
+ srcs: [
+ "AHardwareBuffer.cpp",
+ "ANativeWindow.cpp",
+ ],
+
+ shared_libs: [
+ "libhardware",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libui",
+ ],
+
+ static_libs: [
+ "libarect",
+ ],
+
+ // headers we include in our public headers
+ export_static_lib_headers: [
+ "libarect",
+ ],
+}
diff --git a/libs/nativewindow/MODULE_LICENSE_APACHE2 b/libs/nativewindow/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/nativewindow/MODULE_LICENSE_APACHE2
diff --git a/libs/nativewindow/NOTICE b/libs/nativewindow/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/nativewindow/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/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
similarity index 93%
rename from include/android/hardware_buffer.h
rename to libs/nativewindow/include/android/hardware_buffer.h
index 24e217e..9c08c7b 100644
--- a/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -38,41 +38,48 @@
* Vulkan: VK_FORMAT_R8G8B8A8_UNORM
* OpenGL ES: GL_RGBA8
*/
- AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
+ AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8G8B8A8_UNORM
* OpenGL ES: GL_RGBA8
*/
- AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2,
+ AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8G8B8_UNORM
* OpenGL ES: GL_RGB8
*/
- AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3,
+ AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16
* OpenGL ES: GL_RGB565
*/
- AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4,
+ AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT
* OpenGL ES: GL_RGBA16F
*/
- AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT = 0x16,
+ AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT = 0x16,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_A2R10G10B10_UNORM_PACK32
+ * OpenGL ES: GL_RGB10_A2
+ */
+ AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32 = 0x2b,
/**
* An opaque binary blob format that must have height 1, with width equal to
* the buffer size in bytes.
*/
- AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
+ AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
};
enum {
diff --git a/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
similarity index 97%
rename from include/android/native_window.h
rename to libs/nativewindow/include/android/native_window.h
index 7d8d657..6a46d7f 100644
--- a/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -48,8 +48,6 @@
WINDOW_FORMAT_RGBX_8888 = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
/** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
WINDOW_FORMAT_RGB_565 = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
- /** Red: 16 bits, Green: 16 bits, Blue: 16 bits, Alpha: 16 bits. **/
- WINDOW_FORMAT_RGBA_FP16 = 0x16,
};
struct ANativeWindow;
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
new file mode 100644
index 0000000..f138fa7
--- /dev/null
+++ b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PRIVATE_NATIVE_AHARDWARE_BUFFER_HELPERS_H
+#define ANDROID_PRIVATE_NATIVE_AHARDWARE_BUFFER_HELPERS_H
+
+/*
+ * This file contains utility functions related to AHardwareBuffer, mostly to convert
+ * to/from HAL formats.
+ *
+ * These are PRIVATE methods, so this file can NEVER appear in a public NDK header.
+ * They are used by higher level libraries such as core/jni.
+ */
+
+#include <stdint.h>
+
+struct AHardwareBuffer;
+
+namespace android {
+
+uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
+
+uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format);
+
+void AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage,
+ uint64_t* outProducerUsage, uint64_t* outConsumerUsage);
+
+uint64_t AHardwareBuffer_convertFromGrallocUsageBits(
+ uint64_t producerUsage, uint64_t consumerUsage);
+
+
+class GraphicBuffer;
+const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer);
+GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer);
+AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer);
+
+} // namespace android
+
+#endif // ANDROID_PRIVATE_NATIVE_AHARDWARE_BUFFER_HELPERS_H
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index cfe170d..d1bfa18 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -75,6 +75,16 @@
"libutils",
"liblog",
],
+
+ static_libs: [
+ "libarect",
+ "libmath",
+ ],
+
+ export_static_lib_headers: [
+ "libarect",
+ "libmath",
+ ],
}
subdirs = ["tests"]
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index 8106b16..1414766 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -16,6 +16,8 @@
#include <ui/FenceTime.h>
+#define LOG_TAG "FenceTime"
+
#include <cutils/compiler.h> // For CC_[UN]LIKELY
#include <utils/Log.h>
#include <inttypes.h>
@@ -62,8 +64,11 @@
FenceTime::FenceTime(nsecs_t signalTime)
: mState(Fence::isValidTimestamp(signalTime) ? State::VALID : State::INVALID),
mFence(nullptr),
- mSignalTime(signalTime == Fence::SIGNAL_TIME_PENDING ?
- Fence::SIGNAL_TIME_INVALID : signalTime) {
+ mSignalTime(signalTime) {
+ if (CC_UNLIKELY(mSignalTime == Fence::SIGNAL_TIME_PENDING)) {
+ ALOGE("Pending signal time not allowed after signal.");
+ mSignalTime = Fence::SIGNAL_TIME_INVALID;
+ }
}
void FenceTime::applyTrustedSnapshot(const Snapshot& src) {
@@ -71,7 +76,7 @@
// Applying Snapshot::State::FENCE, could change the valid state of the
// FenceTime, which is not allowed. Callers should create a new
// FenceTime from the snapshot instead.
- ALOGE("FenceTime::applyTrustedSnapshot: Unexpected fence.");
+ ALOGE("applyTrustedSnapshot: Unexpected fence.");
return;
}
@@ -332,16 +337,13 @@
continue;
}
ALOGE_IF(!fenceTime->isValid(),
- "FenceToFenceTimeMap::signalAllForTest: "
- "Signaling invalid fence.");
+ "signalAllForTest: Signaling invalid fence.");
fenceTime->signalForTest(signalTime);
signaled = true;
}
}
- if (!signaled) {
- ALOGE("FenceToFenceTimeMap::signalAllForTest: Nothing to signal.");
- }
+ ALOGE_IF(!signaled, "signalAllForTest: Nothing to signal.");
}
void FenceToFenceTimeMap::garbageCollectLocked() {
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
index 0083f58..64a8b40 100644
--- a/libs/ui/Gralloc1.cpp
+++ b/libs/ui/Gralloc1.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#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 a0bbe63..b8bc6c4 100644
--- a/libs/ui/Gralloc1On0Adapter.cpp
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -18,9 +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..7af55e7 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 {
@@ -28,7 +29,7 @@
Allocator::Allocator()
{
- mAllocator = IAllocator::getService("gralloc");
+ mAllocator = IAllocator::getService();
if (mAllocator != nullptr) {
mAllocator->createClient(
[&](const auto& tmpError, const auto& tmpClient) {
diff --git a/libs/ui/GrallocMapper.cpp b/libs/ui/GrallocMapper.cpp
index b9e9040..8095247 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 {
@@ -30,7 +28,7 @@
Mapper::Mapper()
{
- mMapper = IMapper::getService("gralloc-mapper");
+ mMapper = IMapper::getService();
if (mMapper != nullptr && mMapper->isRemote()) {
LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
}
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 a3b6e18..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,14 +27,11 @@
#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/Rect.h>
+#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index 734472d..e88fdd5 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -27,6 +27,7 @@
case PIXEL_FORMAT_RGBA_8888:
case PIXEL_FORMAT_RGBX_8888:
case PIXEL_FORMAT_BGRA_8888:
+ case PIXEL_FORMAT_RGBA_1010102:
return 4;
case PIXEL_FORMAT_RGB_888:
return 3;
@@ -45,6 +46,7 @@
case PIXEL_FORMAT_RGBA_8888:
case PIXEL_FORMAT_RGBX_8888:
case PIXEL_FORMAT_BGRA_8888:
+ case PIXEL_FORMAT_RGBA_1010102:
return 32;
case PIXEL_FORMAT_RGB_888:
return 24;
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/ui/tools/Android.bp b/libs/ui/tools/Android.bp
new file mode 100644
index 0000000..fb46c2b
--- /dev/null
+++ b/libs/ui/tools/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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_defaults {
+ name: "libui_tools_default",
+ clang_cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
+
+cc_binary {
+ name: "lutgen",
+ cppflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ shared_libs: ["libui"],
+ srcs: ["lutgen.cpp"],
+}
diff --git a/libs/ui/tools/lutgen.cpp b/libs/ui/tools/lutgen.cpp
new file mode 100644
index 0000000..97b0822
--- /dev/null
+++ b/libs/ui/tools/lutgen.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 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 <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <getopt.h>
+
+#include <ui/ColorSpace.h>
+
+using namespace android;
+using namespace std;
+
+uint32_t gSize = 32;
+ColorSpace gColorSpaceSrc = ColorSpace::DisplayP3();
+ColorSpace gColorSpaceDst = ColorSpace::extendedSRGB();
+string gNameSrc = "DisplayP3";
+string gNameDst = "extendedSRGB";
+
+static void printHelp() {
+ cout << "lutgen -d SIZE -s SOURCE -t TARGET <lut file>" << endl;
+ cout << endl;
+ cout << "Generate a 3D LUT to convert between two color spaces." << endl;
+ cout << endl;
+ cout << "If <lut file> ends in .inc, data is generated without the array declaration." << endl;
+ cout << endl;
+ cout << "Options:" << endl;
+ cout << " --help, -h" << endl;
+ cout << " print this message" << endl;
+ cout << " --dimension=, -d" << endl;
+ cout << " the dimension of the 3D LUT. Example: 17 for a 17x17x17 LUT. 32 by default" << endl;
+ cout << " --source=COLORSPACE, -s" << endl;
+ cout << " the source color space, see below for available names. DisplayP3 by default" << endl;
+ cout << " --target=COLORSPACE, -t" << endl;
+ cout << " the target color space, see below for available names. extendedSRGB by default" << endl;
+ cout << endl;
+ cout << "Colorspace names:" << endl;
+ cout << " sRGB" << endl;
+ cout << " linearSRGB" << endl;
+ cout << " extendedSRGB" << endl;
+ cout << " linearExtendedSRGB" << endl;
+ cout << " NTSC" << endl;
+ cout << " BT709" << endl;
+ cout << " BT2020" << endl;
+ cout << " AdobeRGB" << endl;
+ cout << " ProPhotoRGB" << endl;
+ cout << " DisplayP3" << endl;
+ cout << " DCIP3" << endl;
+ cout << " ACES" << endl;
+ cout << " ACEScg" << endl;
+}
+
+static const ColorSpace findColorSpace(const string& name) {
+ if (name == "linearSRGB") return ColorSpace::linearSRGB();
+ if (name == "extendedSRGB") return ColorSpace::extendedSRGB();
+ if (name == "linearExtendedSRGB") return ColorSpace::linearExtendedSRGB();
+ if (name == "NTSC") return ColorSpace::NTSC();
+ if (name == "BT709") return ColorSpace::BT709();
+ if (name == "BT2020") return ColorSpace::BT2020();
+ if (name == "AdobeRGB") return ColorSpace::AdobeRGB();
+ if (name == "ProPhotoRGB") return ColorSpace::ProPhotoRGB();
+ if (name == "DisplayP3") return ColorSpace::DisplayP3();
+ if (name == "DCIP3") return ColorSpace::DCIP3();
+ if (name == "ACES") return ColorSpace::ACES();
+ if (name == "ACEScg") return ColorSpace::ACEScg();
+ return ColorSpace::sRGB();
+}
+
+static int handleCommandLineArgments(int argc, char* argv[]) {
+ static constexpr const char* OPTSTR = "h:d:s:t:";
+ static const struct option OPTIONS[] = {
+ { "help", no_argument, 0, 'h' },
+ { "dimension", required_argument, 0, 'd' },
+ { "source", required_argument, 0, 's' },
+ { "target", required_argument, 0, 't' },
+ { 0, 0, 0, 0 } // termination of the option list
+ };
+
+ int opt;
+ int index = 0;
+
+ while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &index)) >= 0) {
+ string arg(optarg ? optarg : "");
+ switch (opt) {
+ default:
+ case 'h':
+ printHelp();
+ exit(0);
+ break;
+ case 'd':
+ gSize = max(2, min(stoi(arg), 256));
+ break;
+ case 's':
+ gNameSrc = arg;
+ gColorSpaceSrc = findColorSpace(arg);
+ break;
+ case 't':
+ gNameDst = arg;
+ gColorSpaceDst = findColorSpace(arg);
+ break;
+ }
+ }
+
+ return optind;
+}
+
+int main(int argc, char* argv[]) {
+ int optionIndex = handleCommandLineArgments(argc, argv);
+ int numArgs = argc - optionIndex;
+
+ if (numArgs < 1) {
+ printHelp();
+ return 1;
+ }
+
+ bool isInclude = false;
+
+ string filename(argv[optionIndex]);
+ size_t index = filename.find_last_of('.');
+
+ if (index != string::npos) {
+ string extension(filename.substr(index + 1));
+ isInclude = extension == "inc";
+ }
+
+ ofstream outputStream(filename, ios::trunc);
+ if (outputStream.good()) {
+ auto lut = ColorSpace::createLUT(gSize, gColorSpaceSrc, gColorSpaceDst);
+ auto data = lut.get();
+
+ outputStream << "// generated with lutgen " << filename.c_str() << endl;
+ outputStream << "// 3D LUT stored as an RGB16F texture, in GL order" << endl;
+ outputStream << "// Size is " << gSize << "x" << gSize << "x" << gSize << endl;
+
+ string src(gNameSrc);
+ string dst(gNameDst);
+
+ if (!isInclude) {
+ transform(src.begin(), src.end(), src.begin(), ::toupper);
+ transform(dst.begin(), dst.end(), dst.begin(), ::toupper);
+
+ outputStream << "const size_t LUT_" << src << "_TO_" << dst << "_SIZE = " << gSize << endl;
+ outputStream << "const uint16_t LUT_" << src << "_TO_" << dst << "[] = {";
+ } else {
+ outputStream << "// From " << src << " to " << dst << endl;
+ }
+
+ for (size_t z = 0; z < gSize; z++) {
+ for (size_t y = 0; y < gSize; y++) {
+ for (size_t x = 0; x < gSize; x++) {
+ if (x % 4 == 0) outputStream << endl << " ";
+
+ half3 rgb = half3(*data++);
+
+ const uint16_t r = rgb.r.getBits();
+ const uint16_t g = rgb.g.getBits();
+ const uint16_t b = rgb.b.getBits();
+
+ outputStream << "0x" << setfill('0') << setw(4) << hex << r << ", ";
+ outputStream << "0x" << setfill('0') << setw(4) << hex << g << ", ";
+ outputStream << "0x" << setfill('0') << setw(4) << hex << b << ", ";
+ }
+ }
+ }
+
+ if (!isInclude) {
+ outputStream << endl << "}; // end LUT" << endl;
+ }
+
+ outputStream << endl;
+ outputStream.flush();
+ outputStream.close();
+ } else {
+ cerr << "Could not write to file: " << filename << endl;
+ return 1;
+
+ }
+
+ return 0;
+}
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
index 0b9e0cc..fa61c4a 100644
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ b/libs/vr/libbufferhub/bufferhub_tests.cpp
@@ -1,4 +1,3 @@
-#include <android/native_window.h>
#include <gtest/gtest.h>
#include <private/dvr/buffer_hub_client.h>
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
index afed052..f9b6975 100644
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
@@ -3,7 +3,6 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <android/native_window.h>
#include <log/log.h>
#include <system/window.h>
#include <ui/ANativeObjectBase.h>
diff --git a/libs/vr/libdisplay/Android.mk b/libs/vr/libdisplay/Android.mk
index f0e62df..6a9458c 100644
--- a/libs/vr/libdisplay/Android.mk
+++ b/libs/vr/libdisplay/Android.mk
@@ -46,7 +46,8 @@
libui \
libgui \
libhardware \
- libsync
+ libsync \
+ libnativewindow \
staticLibraries := \
libbufferhub \
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/libeds/Android.mk b/libs/vr/libeds/Android.mk
index 373e68e..fd2c56e 100644
--- a/libs/vr/libeds/Android.mk
+++ b/libs/vr/libeds/Android.mk
@@ -36,7 +36,8 @@
libEGL \
libGLESv1_CM \
libGLESv2 \
- libvulkan
+ libvulkan \
+ libandroid
staticLibraries := \
libdisplay \
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/libsensor/Android.mk b/libs/vr/libsensor/Android.mk
index 8c7ad43..89abcb0 100644
--- a/libs/vr/libsensor/Android.mk
+++ b/libs/vr/libsensor/Android.mk
@@ -32,6 +32,7 @@
libhardware \
liblog \
libutils \
+ libandroid \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/libs/vr/libsensor/tests/sensor_app_tests.cpp b/libs/vr/libsensor/tests/sensor_app_tests.cpp
index 0f5bf00..64c9864 100644
--- a/libs/vr/libsensor/tests/sensor_app_tests.cpp
+++ b/libs/vr/libsensor/tests/sensor_app_tests.cpp
@@ -1,6 +1,7 @@
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <math.h>
+#include <inttypes.h>
#include <dvr/graphics.h>
#include <dvr/pose_client.h>
diff --git a/libs/vr/libvrflinger/Android.mk b/libs/vr/libvrflinger/Android.mk
index 1706f30..3450788 100644
--- a/libs/vr/libvrflinger/Android.mk
+++ b/libs/vr/libvrflinger/Android.mk
@@ -56,6 +56,7 @@
libcutils \
liblog \
libhardware \
+ libnativewindow \
libutils \
libEGL \
libGLESv1_CM \
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/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index df84c93..0ac74db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -650,7 +650,7 @@
#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
-#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3156
+#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 48bf676..04f6d6d 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -33,6 +33,7 @@
#include <ui/ANativeObjectBase.h>
#include <ui/Fence.h>
#include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 865313c..4fa6a33 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -80,6 +80,7 @@
"libbinder",
"libutils",
"libui",
+ "libnativewindow",
],
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ef3d7a3..c434d0e 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -28,6 +28,8 @@
#include <EGL/eglext.h>
#include <android/hardware_buffer.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <cutils/memory.h>
@@ -38,8 +40,8 @@
#include <ui/GraphicBuffer.h>
+
#include <utils/KeyedVector.h>
-#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Trace.h>
@@ -81,6 +83,11 @@
*
* NOTE: Both strings MUST have a single space as the last character.
*/
+
+// CLion mistakenly warns about the extern keyword below.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextern-initializer"
+
extern char const * const gBuiltinExtensionString =
"EGL_KHR_get_all_proc_addresses "
"EGL_ANDROID_presentation_time "
@@ -230,6 +237,8 @@
(__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID },
};
+#pragma clang diagnostic pop
+
/*
* These extensions entry-points should not be exposed to applications.
* They're used internally by the Android EGL layer.
@@ -301,7 +310,7 @@
clearError();
egl_display_ptr dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
EGLBoolean res = dp->initialize(major, minor);
@@ -317,7 +326,7 @@
clearError();
egl_display_ptr dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
EGLBoolean res = dp->terminate();
@@ -338,7 +347,7 @@
if (!dp) return EGL_FALSE;
if (num_config==0) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
EGLBoolean res = EGL_FALSE;
@@ -363,7 +372,7 @@
if (!dp) return EGL_FALSE;
if (num_config==0) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
EGLBoolean res = EGL_FALSE;
@@ -395,6 +404,8 @@
case EGL_CONFIG_CAVEAT:
attribCaveat = &attrib_list[attribCount];
break;
+ default:
+ break;
}
attribCount++;
}
@@ -490,14 +501,8 @@
cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT,
&componentType);
- // by default, just pick appropriate RGBA
- EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;
- if (dp->haveExtension("EGL_EXT_pixel_format_float") &&
- (componentType == EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT)) {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
+ EGLint format;
android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
-
EGLint a = 0;
EGLint r, g, b;
r = g = b = 0;
@@ -630,7 +635,7 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t * const s = get_surface(surface);
EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
@@ -650,7 +655,7 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->egl.eglQuerySurface(
@@ -669,7 +674,6 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
setError(EGL_BAD_SURFACE, EGL_FALSE);
- return;
}
}
@@ -728,7 +732,7 @@
ContextRef _c(dp.get(), ctx);
if (!_c.get())
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
egl_context_t * const c = get_context(ctx);
EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
@@ -744,14 +748,14 @@
clearError();
egl_display_ptr dp = validate_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
// If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
// EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
// a valid but uninitialized display.
if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
(draw != EGL_NO_SURFACE) ) {
- if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
}
// get a reference to the object passed in
@@ -762,7 +766,7 @@
// validate the context (if not EGL_NO_CONTEXT)
if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
// EGL_NO_CONTEXT is valid
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
}
// these are the underlying implementation's object
@@ -785,7 +789,7 @@
// no context given, use the implementation of the current context
if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
// calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
- return setError(EGL_BAD_MATCH, EGL_FALSE);
+ return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE);
}
if (cur_c == NULL) {
// no current context
@@ -796,14 +800,14 @@
// retrieve the underlying implementation's draw EGLSurface
if (draw != EGL_NO_SURFACE) {
- if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (!_d.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
d = get_surface(draw);
impl_draw = d->surface;
}
// retrieve the underlying implementation's read EGLSurface
if (read != EGL_NO_SURFACE) {
- if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (!_r.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
r = get_surface(read);
impl_read = r->surface;
}
@@ -827,7 +831,7 @@
} else {
// this will ALOGE the error
egl_connection_t* const cnx = &gEGLImpl;
- result = setError(cnx->egl.eglGetError(), EGL_FALSE);
+ result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE);
}
return result;
}
@@ -842,7 +846,7 @@
if (!dp) return EGL_FALSE;
ContextRef _c(dp.get(), ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
egl_context_t * const c = get_context(ctx);
return c->cnx->egl.eglQueryContext(
@@ -903,7 +907,7 @@
egl_connection_t* const cnx = &gEGLImpl;
if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
return cnx->egl.eglWaitGL();
}
@@ -914,7 +918,7 @@
egl_connection_t* const cnx = &gEGLImpl;
if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
return cnx->egl.eglWaitNative(engine);
}
@@ -1042,7 +1046,7 @@
thread->mQueue.push_back(sync);
thread->mCondition.signal();
thread->mFramesQueued++;
- ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size());
+ ATRACE_INT("GPU Frames Outstanding", int32_t(thread->mQueue.size()));
}
}
@@ -1076,7 +1080,7 @@
Mutex::Autolock lock(mMutex);
mQueue.removeAt(0);
mFramesCompleted++;
- ATRACE_INT("GPU Frames Outstanding", mQueue.size());
+ ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size()));
}
return true;
}
@@ -1099,7 +1103,7 @@
SurfaceRef _s(dp.get(), draw);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(draw);
@@ -1164,7 +1168,7 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
@@ -1182,7 +1186,7 @@
// If we want to support EGL_EXT_client_extensions later, we can return
// the client extension string here instead.
if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
- return setErrorQuiet(EGL_BAD_DISPLAY, nullptr);
+ return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)0);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return (const char *) NULL;
@@ -1196,6 +1200,8 @@
return dp->getExtensionString();
case EGL_CLIENT_APIS:
return dp->getClientApiString();
+ default:
+ break;
}
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
@@ -1216,6 +1222,8 @@
return dp->disp.queryString.extensions;
case EGL_CLIENT_APIS:
return dp->disp.queryString.clientApi;
+ default:
+ break;
}
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
@@ -1234,7 +1242,7 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t * const s = get_surface(surface);
@@ -1242,27 +1250,23 @@
if (!s->win.get()) {
setError(EGL_BAD_SURFACE, EGL_FALSE);
}
- int err = native_window_set_auto_refresh(s->win.get(),
- value ? true : false);
- return (err == NO_ERROR) ? EGL_TRUE :
- setError(EGL_BAD_SURFACE, EGL_FALSE);
+ int err = native_window_set_auto_refresh(s->win.get(), value ? true : false);
+ return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
if (attribute == EGL_TIMESTAMPS_ANDROID) {
if (!s->win.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
- int err = native_window_enable_frame_timestamps(
- s->win.get(), value ? true : false);
- return (err == NO_ERROR) ? EGL_TRUE :
- setError(EGL_BAD_SURFACE, EGL_FALSE);
+ int err = native_window_enable_frame_timestamps(s->win.get(), value ? true : false);
+ return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
if (s->cnx->egl.eglSurfaceAttrib) {
return s->cnx->egl.eglSurfaceAttrib(
dp->disp.dpy, s->surface, attribute, value);
}
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
EGLBoolean eglBindTexImage(
@@ -1275,14 +1279,14 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglBindTexImage) {
return s->cnx->egl.eglBindTexImage(
dp->disp.dpy, s->surface, buffer);
}
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
EGLBoolean eglReleaseTexImage(
@@ -1295,14 +1299,14 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglReleaseTexImage) {
return s->cnx->egl.eglReleaseTexImage(
dp->disp.dpy, s->surface, buffer);
}
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
@@ -1332,7 +1336,7 @@
egl_connection_t* const cnx = &gEGLImpl;
if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
EGLBoolean res;
if (cnx->egl.eglWaitClient) {
@@ -1348,7 +1352,7 @@
clearError();
if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
// bind this API on all EGLs
@@ -1365,7 +1369,7 @@
clearError();
if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
egl_connection_t* const cnx = &gEGLImpl;
@@ -1423,14 +1427,14 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglLockSurfaceKHR) {
return s->cnx->egl.eglLockSurfaceKHR(
dp->disp.dpy, s->surface, attrib_list);
}
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
@@ -1442,13 +1446,13 @@
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->egl.eglUnlockSurfaceKHR) {
return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
}
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
@@ -1546,7 +1550,7 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
- EGLBoolean result = EGL_FALSE;
+ EGLint result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
result = cnx->egl.eglClientWaitSyncKHR(
@@ -1991,9 +1995,7 @@
if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
- // FIXME: remove this dangerous reinterpret_cast.
- const GraphicBuffer* graphicBuffer =
- reinterpret_cast<const GraphicBuffer*>(buffer);
+ const GraphicBuffer* graphicBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
return static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
}
@@ -2005,7 +2007,7 @@
clearError();
if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE);
}
EGLuint64NV ret = 0;
@@ -2015,7 +2017,7 @@
return cnx->egl.eglGetSystemTimeFrequencyNV();
}
- return setErrorQuiet(EGL_BAD_DISPLAY, 0);
+ return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0);
}
EGLuint64NV eglGetSystemTimeNV()
@@ -2023,7 +2025,7 @@
clearError();
if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE);
}
EGLuint64NV ret = 0;
@@ -2033,7 +2035,7 @@
return cnx->egl.eglGetSystemTimeNV();
}
- return setErrorQuiet(EGL_BAD_DISPLAY, 0);
+ return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0);
}
// ----------------------------------------------------------------------------
@@ -2071,18 +2073,18 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
egl_surface_t const * const s = get_surface(surface);
if (!s->win.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
uint64_t nextFrameId = 0;
@@ -2092,7 +2094,7 @@
// This should not happen. Return an error that is not in the spec
// so it's obvious something is very wrong.
ALOGE("eglGetNextFrameId: Unexpected error.");
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
}
*frameId = nextFrameId;
@@ -2106,18 +2108,18 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
egl_surface_t const * const s = get_surface(surface);
if (!s->win.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
nsecs_t* compositeDeadline = nullptr;
@@ -2136,7 +2138,7 @@
compositeToPresentLatency = &values[i];
break;
default:
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
}
@@ -2147,12 +2149,12 @@
case NO_ERROR:
return EGL_TRUE;
case INVALID_OPERATION:
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
default:
// This should not happen. Return an error that is not in the spec
// so it's obvious something is very wrong.
ALOGE("eglGetCompositorTiming: Unexpected error.");
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
}
}
@@ -2163,19 +2165,19 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
egl_surface_t const * const s = get_surface(surface);
ANativeWindow* window = s->win.get();
if (!window) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
switch (name) {
@@ -2196,25 +2198,25 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
egl_surface_t const * const s = get_surface(surface);
if (!s->win.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
nsecs_t* requestedPresentTime = nullptr;
nsecs_t* acquireTime = nullptr;
nsecs_t* latchTime = nullptr;
nsecs_t* firstRefreshStartTime = nullptr;
- nsecs_t* GLCompositionDoneTime = nullptr;
+ nsecs_t* gpuCompositionDoneTime = nullptr;
nsecs_t* lastRefreshStartTime = nullptr;
nsecs_t* displayPresentTime = nullptr;
nsecs_t* displayRetireTime = nullptr;
@@ -2238,8 +2240,8 @@
case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
lastRefreshStartTime = &values[i];
break;
- case EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID:
- GLCompositionDoneTime = &values[i];
+ case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
+ gpuCompositionDoneTime = &values[i];
break;
case EGL_DISPLAY_PRESENT_TIME_ANDROID:
displayPresentTime = &values[i];
@@ -2254,29 +2256,29 @@
releaseTime = &values[i];
break;
default:
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
}
}
status_t ret = native_window_get_frame_timestamps(s->win.get(), frameId,
requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
- lastRefreshStartTime, GLCompositionDoneTime, displayPresentTime,
+ lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
displayRetireTime, dequeueReadyTime, releaseTime);
switch (ret) {
- case NO_ERROR:
- return EGL_TRUE;
- case NAME_NOT_FOUND:
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- case INVALID_OPERATION:
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- case BAD_VALUE:
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- default:
- // This should not happen. Return an error that is not in the spec
- // so it's obvious something is very wrong.
- ALOGE("eglGetFrameTimestamps: Unexpected error.");
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ case NO_ERROR:
+ return EGL_TRUE;
+ case NAME_NOT_FOUND:
+ return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
+ case INVALID_OPERATION:
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ case BAD_VALUE:
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ default:
+ // This should not happen. Return an error that is not in the spec
+ // so it's obvious something is very wrong.
+ ALOGE("eglGetFrameTimestamps: Unexpected error.");
+ return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
}
}
@@ -2287,19 +2289,19 @@
const egl_display_ptr dp = validate_display(dpy);
if (!dp) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
egl_surface_t const * const s = get_surface(surface);
ANativeWindow* window = s->win.get();
if (!window) {
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
switch (timestamp) {
@@ -2311,20 +2313,18 @@
case EGL_COMPOSITION_LATCH_TIME_ANDROID:
case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
- case EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID:
+ case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
case EGL_DEQUEUE_READY_TIME_ANDROID:
case EGL_READS_DONE_TIME_ANDROID:
return EGL_TRUE;
case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
int value = 0;
- window->query(window,
- NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
+ window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
return value == 0 ? EGL_FALSE : EGL_TRUE;
}
case EGL_DISPLAY_RETIRE_TIME_ANDROID: {
int value = 0;
- window->query(window,
- NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &value);
+ window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &value);
return value == 0 ? EGL_FALSE : EGL_TRUE;
}
default:
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index d0ed8e1..e32d9e6 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -90,7 +90,7 @@
EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
- EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3156
+ EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
@@ -189,10 +189,10 @@
that indicates the subsequent frame was not submitted in time to be
latched by the compositor. Note: The value may not be updated for
every display refresh if the compositor becomes idle.
- - EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID - The time at which the
- compositor's rendering work for this frame finished. This will be zero
- if composition was handled by the display and the compositor didn't do
- any rendering.
+ - EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID - The time at which
+ the compositor's rendering work for this frame finished. This will be
+ zero if composition was handled by the display and the compositor
+ didn't do any rendering.
- EGL_DISPLAY_PRESENT_TIME_ANDROID - The time at which this frame
started to scan out to the physical display.
- EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was
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/specs/README b/opengl/specs/README
index 0c49023..a7a9785 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -28,7 +28,7 @@
0x3153 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x3154 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x3155 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3156 EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3156 EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x3157 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x3158 EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x3159 EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 1cd40b3..1b3086b 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -106,9 +106,9 @@
EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
struct DummyConsumer : public BnConsumerListener {
- virtual void onFrameAvailable(const BufferItem& /* item */) {}
- virtual void onBuffersReleased() {}
- virtual void onSidebandStreamChanged() {}
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
};
// Create a EGLSurface
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
index 693fba4..13337c2 100644
--- a/opengl/tests/hwc/Android.mk
+++ b/opengl/tests/hwc/Android.mk
@@ -25,6 +25,8 @@
LOCAL_C_INCLUDES += system/extras/tests/include \
$(call include-path-for, opengl-tests-includes) \
+LOCAL_STATIC_LIBRARIES := libarect
+
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
index 4407e7b..0f1c925 100644
--- a/opengl/tests/lib/Android.mk
+++ b/opengl/tests/lib/Android.mk
@@ -24,4 +24,6 @@
LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
+LOCAL_STATIC_LIBRARIES := libarect
+
include $(BUILD_STATIC_LIBRARY)
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 9e81a8c..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
@@ -206,6 +202,7 @@
liblog \
libbinder \
libutils \
+ libui \
libdl
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
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/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index d3d0d51..ae6e0cc 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -27,15 +27,16 @@
#include <utils/String8.h>
#include <log/log.h>
-#include <ui/Rect.h>
-
#include <EGL/egl.h>
#include <hardware/hardware.h>
#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
#include <gui/GraphicBufferAlloc.h>
#include <gui/Surface.h>
+
#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
#include "FramebufferSurface.h"
#include "HWComposer.h"
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index a25e8a1..e49e734 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -23,9 +23,8 @@
#include "HWC2.h"
#include "ComposerHal.h"
-#include <gfx/FloatRect.h>
-
#include <ui/Fence.h>
+#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
#include <ui/Region.h>
@@ -74,12 +73,12 @@
}
using android::Fence;
+using android::FloatRect;
using android::GraphicBuffer;
using android::HdrCapabilities;
using android::Rect;
using android::Region;
using android::sp;
-using android::gfx::FloatRect;
using android::hardware::Return;
using android::hardware::Void;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 93eb999..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>
@@ -38,12 +38,10 @@
namespace android {
class Fence;
+ class FloatRect;
class GraphicBuffer;
class Rect;
class Region;
- namespace gfx {
- class FloatRect;
- }
namespace Hwc2 {
class Composer;
}
@@ -410,7 +408,7 @@
[[clang::warn_unused_result]] Error setSidebandStream(
const native_handle_t* stream);
[[clang::warn_unused_result]] Error setSourceCrop(
- const android::gfx::FloatRect& crop);
+ const android::FloatRect& crop);
[[clang::warn_unused_result]] Error setTransform(Transform transform);
[[clang::warn_unused_result]] Error setVisibleRegion(
const android::Region& region);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index a6171f5..4187890 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,16 +958,15 @@
}
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);
-
if (!mChanges) {
if (!mDevice.prepareAllDisplays()) {
return Error::BadDisplay;
}
+ } else {
+ ALOGE("Validate was called more than once!");
}
*outNumTypes = mChanges->getNumTypes();
@@ -1055,10 +980,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 +1012,7 @@
layer->setZ(z);
mLayers.emplace(std::move(layer));
- mZIsDirty = true;
+ markGeometryChanged();
return Error::None;
}
@@ -1159,8 +1081,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 +1159,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 +1172,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
@@ -1268,88 +1187,45 @@
return false;
}
- 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 +1237,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 +1278,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 +1311,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 +1329,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 +1344,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 +1354,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 +1374,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 +1383,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 +1393,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 +1401,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 +1461,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 +1483,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 +1523,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 +1531,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 +1580,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 +1592,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 +1603,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 +1625,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 +1633,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 +1689,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 +1708,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 +1753,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 +1796,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 +1831,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 +1858,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 +1878,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 +1922,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 +1934,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 +2046,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,169 +2085,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()
-{
- ALOGV("populateCapabilities");
+void HWC2On1Adapter::populateCapabilities() {
if (mHwc1MinorVersion >= 3U) {
int supportedTypes = 0;
auto result = mHwc1Device->query(mHwc1Device,
@@ -2408,8 +2229,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 +2241,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 +2259,17 @@
return std::make_tuple(layer.get(), Error::None);
}
-void HWC2On1Adapter::populatePrimary()
-{
- ALOGV("populatePrimary");
-
+void HWC2On1Adapter::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 +2286,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 +2310,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 +2354,90 @@
auto displayId = mHwc1DisplayMap[hwc1Id];
auto& display = mDisplays[displayId];
- display->setReceivedContents(std::move(requestedContents[hwc1Id]));
+ display->generateChanges();
}
return true;
}
-Error HWC2On1Adapter::setAllDisplays()
-{
+void dumpHWC1Message(hwc_composer_device_1* device, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ ALOGV("*****************************");
+ size_t displayId = 0;
+ while (displayId < numDisplays) {
+ hwc_display_contents_1_t* display = displays[displayId];
+
+ ALOGV("hwc_display_contents_1_t[%zu] @0x%p", displayId, display);
+ if (display == nullptr) {
+ displayId++;
+ continue;
+ }
+ ALOGV(" retirefd:0x%08x", display->retireFenceFd);
+ ALOGV(" outbuf :0x%p", display->outbuf);
+ ALOGV(" outbuffd:0x%08x", display->outbufAcquireFenceFd);
+ ALOGV(" flags :0x%08x", display->flags);
+ for(size_t layerId=0 ; layerId < display->numHwLayers ; layerId++) {
+ hwc_layer_1_t& layer = display->hwLayers[layerId];
+ ALOGV(" Layer[%zu]:", layerId);
+ ALOGV(" composition : 0x%08x", layer.compositionType);
+ ALOGV(" hints : 0x%08x", layer.hints);
+ ALOGV(" flags : 0x%08x", layer.flags);
+ ALOGV(" handle : 0x%p", layer.handle);
+ ALOGV(" transform : 0x%08x", layer.transform);
+ ALOGV(" blending : 0x%08x", layer.blending);
+ ALOGV(" sourceCropf : %f, %f, %f, %f",
+ layer.sourceCropf.left,
+ layer.sourceCropf.top,
+ layer.sourceCropf.right,
+ layer.sourceCropf.bottom);
+ ALOGV(" displayFrame : %d, %d, %d, %d",
+ layer.displayFrame.left,
+ layer.displayFrame.left,
+ layer.displayFrame.left,
+ layer.displayFrame.left);
+ hwc_region_t& visReg = layer.visibleRegionScreen;
+ ALOGV(" visibleRegionScreen: #0x%08zx[@0x%p]",
+ visReg.numRects,
+ visReg.rects);
+ for (size_t visRegId=0; visRegId < visReg.numRects ; visRegId++) {
+ if (layer.visibleRegionScreen.rects == nullptr) {
+ ALOGV(" null");
+ } else {
+ ALOGV(" visibleRegionScreen[%zu] %d, %d, %d, %d",
+ visRegId,
+ visReg.rects[visRegId].left,
+ visReg.rects[visRegId].top,
+ visReg.rects[visRegId].right,
+ visReg.rects[visRegId].bottom);
+ }
+ }
+ ALOGV(" acquireFenceFd : 0x%08x", layer.acquireFenceFd);
+ ALOGV(" releaseFenceFd : 0x%08x", layer.releaseFenceFd);
+ ALOGV(" planeAlpha : 0x%08x", layer.planeAlpha);
+ if (getMinorVersion(device) < 5)
+ continue;
+ ALOGV(" surfaceDamage : #0x%08zx[@0x%p]",
+ layer.surfaceDamage.numRects,
+ layer.surfaceDamage.rects);
+ for (size_t sdId=0; sdId < layer.surfaceDamage.numRects ; sdId++) {
+ if (layer.surfaceDamage.rects == nullptr) {
+ ALOGV(" null");
+ } else {
+ ALOGV(" surfaceDamage[%zu] %d, %d, %d, %d",
+ sdId,
+ layer.surfaceDamage.rects[sdId].left,
+ layer.surfaceDamage.rects[sdId].top,
+ layer.surfaceDamage.rects[sdId].right,
+ layer.surfaceDamage.rects[sdId].bottom);
+ }
+ }
+ }
+ displayId++;
+ }
+ ALOGV("-----------------------------");
+}
+
+Error HWC2On1Adapter::setAllDisplays() {
ATRACE_CALL();
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
@@ -2576,6 +2461,7 @@
ALOGV("Calling HWC1 set");
{
ATRACE_NAME("HWC1 set");
+ //dumpHWC1Message(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data());
mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
mHwc1Contents.data());
}
@@ -2598,14 +2484,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 +2502,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 +2511,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 +2531,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 +2593,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/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index 0bfc56e..5b5f1cf 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -1031,7 +1031,7 @@
virtual void setFrame(const Rect& frame) {
getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame);
}
- virtual void setCrop(const gfx::FloatRect& crop) {
+ virtual void setCrop(const FloatRect& crop) {
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop);
} else {
@@ -1160,6 +1160,7 @@
case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888");
case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888");
case PIXEL_FORMAT_RGBA_FP16: return String8("RGBA_FP16");
+ case PIXEL_FORMAT_RGBA_1010102: return String8("RGBA_1010102");
case PIXEL_FORMAT_RGB_888: return String8("RGB_888");
case PIXEL_FORMAT_RGB_565: return String8("RGB_565");
case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888");
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index a94bc1e..f64d69a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -48,14 +48,12 @@
// ---------------------------------------------------------------------------
class Fence;
+class FloatRect;
class GraphicBuffer;
class NativeHandle;
class Region;
class String8;
class SurfaceFlinger;
-namespace gfx {
- class FloatRect;
-}
class HWComposer
{
@@ -172,7 +170,7 @@
virtual void setBlending(uint32_t blending) = 0;
virtual void setTransform(uint32_t transform) = 0;
virtual void setFrame(const Rect& frame) = 0;
- virtual void setCrop(const gfx::FloatRect& crop) = 0;
+ virtual void setCrop(const FloatRect& crop) = 0;
virtual void setVisibleRegionScreen(const Region& reg) = 0;
virtual void setSurfaceDamage(const Region& reg) = 0;
virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 5f3c388..c5a4f99 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -19,6 +19,7 @@
#include "HWComposer.h"
#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
#include <gui/IProducerListener.h>
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 2636667..fb5fcc8 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -179,7 +179,7 @@
// slot. Both mProducerSlotSource and mProducerBuffers are indexed by a
// "producer slot"; see the mapSlot*() functions.
uint64_t mProducerSlotSource;
- sp<GraphicBuffer> mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+ sp<GraphicBuffer> mProducerBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
// The QueueBufferOutput with the latest info from the sink, and with the
// transform hint cleared. Since we defer queueBuffer from the GLES driver
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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a854aec..2f83c0e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -38,6 +38,7 @@
#include <ui/PixelFormat.h>
#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include "clz.h"
@@ -76,13 +77,14 @@
mPendingStates(),
mQueuedFrames(0),
mSidebandStreamChanged(false),
+ mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mOverrideScalingMode(-1),
mCurrentOpacity(true),
mBufferLatched(false),
mCurrentFrameNumber(0),
- mPreviousFrameNumber(-1U),
+ mPreviousFrameNumber(0),
mRefreshPending(false),
mFrameLatencyNeeded(false),
mFiltering(false),
@@ -477,10 +479,10 @@
return activeCrop;
}
-gfx::FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
+FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
// the content crop is the area of the content that gets scaled to the
// layer's size. This is in buffer space.
- gfx::FloatRect crop = getContentCrop().toFloatRect();
+ FloatRect crop = getContentCrop().toFloatRect();
// In addition there is a WM-specified crop we pull from our drawing state.
const State& s(getDrawingState());
@@ -674,7 +676,7 @@
hwcInfo.displayFrame = transformedFrame;
}
- gfx::FloatRect sourceCrop = computeCrop(displayDevice);
+ FloatRect sourceCrop = computeCrop(displayDevice);
error = hwcLayer->setSourceCrop(sourceCrop);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
@@ -1305,6 +1307,7 @@
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
return false;
}
// in all other case, we have no blending (also for unknown formats)
@@ -1903,8 +1906,10 @@
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
glDoneFence, presentFence, compositorTiming);
- mFrameEventHistory.addRetire(mPreviousFrameNumber,
- retireFence);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRetire(mPreviousFrameNumber,
+ retireFence);
+ }
}
// Update mFrameTracker.
@@ -1942,14 +1947,19 @@
#ifdef USE_HWC2
void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
- mSurfaceFlingerConsumer->releasePendingBuffer();
+ if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
+ return;
+ }
+
auto releaseFenceTime = std::make_shared<FenceTime>(
mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
mReleaseTimeline.push(releaseFenceTime);
Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addRelease(
- mPreviousFrameNumber, dequeueReadyTime, std::move(releaseFenceTime));
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber,
+ dequeueReadyTime, std::move(releaseFenceTime));
+ }
}
#endif
@@ -2135,8 +2145,10 @@
auto releaseFenceTime = std::make_shared<FenceTime>(
mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
mReleaseTimeline.push(releaseFenceTime);
- mFrameEventHistory.addRelease(
- mPreviousFrameNumber, latchTime, std::move(releaseFenceTime));
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber,
+ latchTime, std::move(releaseFenceTime));
+ }
#endif
}
@@ -2338,7 +2350,7 @@
const Rect& frame = hwcInfo.displayFrame;
result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top,
frame.right, frame.bottom);
- const gfx::FloatRect& crop = hwcInfo.sourceCrop;
+ const FloatRect& crop = hwcInfo.sourceCrop;
result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top,
crop.right, crop.bottom);
@@ -2371,6 +2383,11 @@
mFrameEventHistory.dump(result);
}
+void Layer::onDisconnect() {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.onDisconnect();
+}
+
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta *outDelta) {
Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8227dae..c5fea73 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -27,8 +27,6 @@
#include <utils/String8.h>
#include <utils/Timers.h>
-#include <gfx/FloatRect.h>
-
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
@@ -446,6 +444,7 @@
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
+ void onDisconnect();
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
FrameEventHistoryDelta* outDelta);
@@ -513,7 +512,7 @@
uint32_t getEffectiveUsage(uint32_t usage) const;
- gfx::FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
+ FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
// Compute the initial crop as specified by parent layers and the SurfaceControl
// for this layer. Does not include buffer crop from the IGraphicBufferProducer
// client, as that should not affect child clipping. Returns in screen space.
@@ -657,7 +656,7 @@
FenceTimeline mReleaseTimeline;
// main thread
- int mActiveBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ int mActiveBufferSlot;
sp<GraphicBuffer> mActiveBuffer;
sp<NativeHandle> mSidebandStream;
Rect mCurrentCrop;
@@ -694,7 +693,7 @@
HWC2::Composition compositionType;
bool clearClientTarget;
Rect displayFrame;
- gfx::FloatRect sourceCrop;
+ FloatRect sourceCrop;
};
std::unordered_map<int32_t, HWCInfo> mHwcLayers;
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 2bc0605..5ca7d39 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -16,6 +16,8 @@
#include "LayerRejecter.h"
+#include <gui/BufferItem.h>
+
#include "clz.h"
#define DEBUG_RESIZE 0
@@ -123,4 +125,4 @@
return false;
}
-} // namespace android
\ No newline at end of file
+} // 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 462e5a6..1a9727a 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");
@@ -639,7 +641,7 @@
FrameEvent::LATCH,
FrameEvent::FIRST_REFRESH_START,
FrameEvent::LAST_REFRESH_START,
- FrameEvent::GL_COMPOSITION_DONE,
+ FrameEvent::GPU_COMPOSITION_DONE,
getHwComposer().presentFenceRepresentsStartOfScanout() ?
FrameEvent::DISPLAY_PRESENT : FrameEvent::DISPLAY_RETIRE,
FrameEvent::DEQUEUE_READY,
@@ -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;
@@ -1265,6 +1267,7 @@
Fence::SIGNAL_TIME_PENDING);
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (mPropagateBackpressure && frameMissed) {
+ ALOGD("Backpressure trigger, skipping transaction & refresh!");
signalLayerUpdate();
break;
}
@@ -1549,46 +1552,49 @@
ALOGV("rebuildLayerStacks");
// rebuild the visible layer list per screen
- if (CC_UNLIKELY(mVisibleRegionsDirty)) {
- ATRACE_CALL();
- mVisibleRegionsDirty = false;
- invalidateHwcGeometry();
-
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- Region opaqueRegion;
- Region dirtyRegion;
- Vector<sp<Layer>> layersSortedByZ;
- const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
- const Transform& tr(displayDevice->getTransform());
- const Rect bounds(displayDevice->getBounds());
- if (displayDevice->isDisplayOn()) {
- computeVisibleRegions(
- displayDevice->getLayerStack(), dirtyRegion,
- opaqueRegion);
-
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->getLayerStack() == displayDevice->getLayerStack()) {
- Region drawRegion(tr.transform(
- layer->visibleNonTransparentRegion));
- drawRegion.andSelf(bounds);
- if (!drawRegion.isEmpty()) {
- layersSortedByZ.add(layer);
- } else {
- // Clear out the HWC layer if this layer was
- // previously visible, but no longer is
- layer->setHwcLayer(displayDevice->getHwcDisplayId(),
- nullptr);
- }
- }
- });
- }
- displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
- displayDevice->undefinedRegion.set(bounds);
- displayDevice->undefinedRegion.subtractSelf(
- tr.transform(opaqueRegion));
- displayDevice->dirtyRegion.orSelf(dirtyRegion);
- }
+ if (CC_LIKELY(mVisibleRegionsDirty)) {
+ return;
}
+
+ ATRACE_NAME("rebuildLayerStacks VR Dirty");
+ mVisibleRegionsDirty = false;
+ invalidateHwcGeometry();
+
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ Region opaqueRegion;
+ Region dirtyRegion;
+ Vector<sp<Layer>> layersSortedByZ;
+ const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
+ const Transform& tr(displayDevice->getTransform());
+ const Rect bounds(displayDevice->getBounds());
+ if (displayDevice->isDisplayOn()) {
+ computeVisibleRegions(
+ displayDevice->getLayerStack(), dirtyRegion,
+ opaqueRegion);
+
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (layer->getLayerStack() == displayDevice->getLayerStack()) {
+ Region drawRegion(tr.transform(
+ layer->visibleNonTransparentRegion));
+ drawRegion.andSelf(bounds);
+ if (!drawRegion.isEmpty()) {
+ layersSortedByZ.add(layer);
+ } else {
+ // Clear out the HWC layer if this layer was
+ // previously visible, but no longer is
+ layer->setHwcLayer(displayDevice->getHwcDisplayId(),
+ nullptr);
+ }
+ }
+ });
+ }
+ displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+ displayDevice->undefinedRegion.set(bounds);
+ displayDevice->undefinedRegion.subtractSelf(
+ tr.transform(opaqueRegion));
+ displayDevice->dirtyRegion.orSelf(dirtyRegion);
+ }
+
}
void SurfaceFlinger::setUpHWComposer() {
@@ -2539,11 +2545,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/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 942af13..2fcbdba 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -23,6 +23,7 @@
#include <private/gui/SyncFeatures.h>
#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
#include <utils/Errors.h>
#include <utils/NativeHandle.h>
@@ -211,20 +212,21 @@
}
}
-void SurfaceFlingerConsumer::releasePendingBuffer()
+bool SurfaceFlingerConsumer::releasePendingBuffer()
{
if (!mPendingRelease.isPending) {
ALOGV("Pending buffer already released");
- return;
+ return false;
}
ALOGV("Releasing pending buffer");
Mutex::Autolock lock(mMutex);
status_t result = releaseBufferLocked(mPendingRelease.currentTexture,
mPendingRelease.graphicBuffer, mPendingRelease.display,
mPendingRelease.fence);
- ALOGE_IF(result != NO_ERROR, "releasePendingBuffer failed: %s (%d)",
+ ALOGE_IF(result < NO_ERROR, "releasePendingBuffer failed: %s (%d)",
strerror(-result), result);
mPendingRelease = PendingRelease();
+ return true;
}
#endif
@@ -261,6 +263,13 @@
}
}
+void SurfaceFlingerConsumer::onDisconnect() {
+ sp<Layer> l = mLayer.promote();
+ if (l.get()) {
+ l->onDisconnect();
+ }
+}
+
void SurfaceFlingerConsumer::addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta *outDelta) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 7713ed2..cfa70ed 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -18,6 +18,8 @@
#define ANDROID_SURFACEFLINGERCONSUMER_H
#include "DispSync.h"
+
+#include <ui/Region.h>
#include <gui/GLConsumer.h>
namespace android {
@@ -82,10 +84,11 @@
sp<Fence> getPrevFinalReleaseFence() const;
#ifdef USE_HWC2
virtual void setReleaseFence(const sp<Fence>& fence) override;
- void releasePendingBuffer();
+ bool releasePendingBuffer();
#endif
- virtual void addAndGetFrameTimestamps(
+ void onDisconnect() override;
+ void addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 477eb27..5aaaab1 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -640,7 +640,7 @@
FrameEvent::LATCH,
FrameEvent::FIRST_REFRESH_START,
FrameEvent::LAST_REFRESH_START,
- FrameEvent::GL_COMPOSITION_DONE,
+ FrameEvent::GPU_COMPOSITION_DONE,
FrameEvent::DISPLAY_RETIRE,
FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
@@ -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/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index 4ba2373..0db909c 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -33,7 +33,8 @@
libhardware \
liblog \
libsync \
- libutils
+ libutils \
+ libgui
include $(CLEAR_VARS)
# Don't strip symbols so we see stack traces in logcat.
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/application.cpp b/services/vr/vr_window_manager/application.cpp
index 33cd499..467e95e 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -1,5 +1,6 @@
#include "application.h"
+#include <inttypes.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <binder/IServiceManager.h>
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 d7d0e5b..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,12 @@
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;
+ }
+
if (mapper.getDimensions(handle, &width, &height) ||
mapper.getStride(handle, &stride) ||
mapper.getFormat(handle, &format) ||
@@ -61,11 +66,13 @@
// 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 buffer");
+ ALOGE("Failed to register cloned buffer");
return nullptr;
}
@@ -78,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)
@@ -97,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;
}
@@ -140,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;
}
@@ -149,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;
}
@@ -197,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;
}
////////////////////////////////////////////////////////////////////////////////
@@ -226,8 +223,6 @@
VrHwc::~VrHwc() {}
-bool VrHwc::Initialize() { return display_.Initialize(); }
-
bool VrHwc::hasCapability(Capability capability) const { return false; }
void VrHwc::removeClient() {
@@ -262,7 +257,7 @@
std::lock_guard<std::mutex> guard(mutex_);
HwcLayer* layer = display_.CreateLayer();
- *outLayer = layer->id;
+ *outLayer = layer->info.id;
return Error::NONE;
}
@@ -448,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;
}
@@ -661,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 b29d175..05ec64a 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -11,37 +11,6 @@
namespace {
-sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) {
- GraphicBufferMapper& mapper = GraphicBufferMapper::get();
- if (mapper.registerBuffer(handle) != OK) {
- ALOGE("Failed to register buffer");
- return nullptr;
- }
-
- uint32_t width = 0, height = 0, stride = 0, layer_count = 1;
- uint64_t producer_usage = 0, consumer_usage = 0;
- int32_t format = 0;
-
- if (mapper.getDimensions(handle, &width, &height) ||
- mapper.getStride(handle, &stride) ||
- mapper.getFormat(handle, &format) ||
- mapper.getProducerUsage(handle, &producer_usage) ||
- mapper.getConsumerUsage(handle, &consumer_usage)) {
- ALOGE("Failed to read handle properties");
- return nullptr;
- }
-
- // This will only succeed if gralloc has GRALLOC1_CAPABILITY_LAYERED_BUFFERS
- // capability. Otherwise assume a count of 1.
- mapper.getLayerCount(handle, &layer_count);
-
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- width, height, format, layer_count, producer_usage, consumer_usage,
- stride, native_handle_clone(handle), true);
-
- return buffer;
-}
-
HwcCallback::FrameStatus GetFrameStatus(const HwcCallback::Frame& frame) {
for (const auto& layer : frame.layers()) {
// If there is no fence it means the buffer is already finished.
@@ -69,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{
@@ -84,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_;
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index fb8e3ce..b82cbb4 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -49,4 +49,5 @@
@internal type void* HINSTANCE
@internal type void* HWND
@internal type void* HANDLE
+@internal type u32 DWORD
@internal class SECURITY_ATTRIBUTES {}
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index a89fed9..cfeeeef 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -45,116 +45,154 @@
// API keyword, but needs special handling by some templates
define NULL_HANDLE 0
+// 1
@extension("VK_KHR_surface") define VK_KHR_SURFACE_SPEC_VERSION 25
@extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface"
+// 2
@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 68
@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
+// 3
@extension("VK_KHR_display") define VK_KHR_DISPLAY_SPEC_VERSION 21
@extension("VK_KHR_display") define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display"
+// 4
@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9
@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain"
+// 5
@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_NAME "VK_KHR_xlib_surface"
+// 6
@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_NAME "VK_KHR_xcb_surface"
+// 7
@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5
@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface"
+// 8
@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION 4
@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME "VK_KHR_mir_surface"
+// 9
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME "VK_KHR_android_surface"
+// 10
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface"
-@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
-@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_NAME "VK_KHR_incremental_present"
-
-@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 6
+// 11
+@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 7
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer"
-@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
-@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_NAME "VK_GOOGLE_display_timing"
-
+// 12
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 4
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report"
+// 13
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME "VK_NV_glsl_shader"
+// 15
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
+// 16
@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1
@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_NAME "VK_IMG_filter_cubic"
+// 19
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME "VK_AMD_rasterization_order"
+// 21
@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
+// 22
@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
+// 23
@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3
@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME "VK_EXT_debug_marker"
+// 26
@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_SPEC_VERSION 1
@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader"
+// 27
@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
-@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
-@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
-
-@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
-@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
-
-@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
-@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
-
-@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
-@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
-
-@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
-@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
-
+// 28
@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
+// 34
+@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
+@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
+
+// 36
+@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
+@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
+
+// 37
+@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
+@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
+
+// 38
+@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
+@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
+
+// 56
@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities"
+// 57
@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1
@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory"
+// 58
@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
+// 59
@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1
@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
+// 60
+@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
+@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
+
+// 62
@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
+// 85
+@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
+@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_NAME "VK_KHR_incremental_present"
+
+// 87
@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
+// 93
+@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
+@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_NAME "VK_GOOGLE_display_timing"
+
+// 106
+@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_SPEC_VERSION 1
+@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
+
+// 112
@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
-
-
/////////////
// Types //
/////////////
@@ -650,28 +688,14 @@
VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
//@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
-
- //@extension("VK_IMG_format_pvrtc")
- VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
+ VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
+ VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
+ VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
+ VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
+ VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
+ VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
+ VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
+ VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
}
/// Structure type enumerant
@@ -761,6 +785,7 @@
//@extension("VK_ANDROID_native_buffer")
VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID = 1000010000,
VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID = 1000010001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID = 1000010002,
//@extension("VK_GOOGLE_display_timing")
VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
@@ -773,87 +798,49 @@
//@extension("VK_EXT_debug_marker")
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
-
- //@extension("VK_EXT_debug_marker")
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
-
- //@extension("VK_EXT_debug_marker")
VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
//@extension("VK_NV_dedicated_allocation")
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
-
- //@extension("VK_NV_dedicated_allocation")
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
-
- //@extension("VK_NV_dedicated_allocation")
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
//@extension("VK_NV_external_memory")
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
-
- //@extension("VK_NV_external_memory")
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
//@extension("VK_NV_external_memory_win32")
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
-
- //@extension("VK_NV_external_memory_win32")
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
//@extension("VK_NV_win32_keyed_mutex")
VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
//@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
-
- //@extension("VK_KHR_get_physical_device_properties2")
- VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
-
- //@extension("VK_KHR_get_physical_device_properties2")
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
+ VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
+ VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
//@extension("VK_EXT_validation_flags")
- VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
+ VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
//@extension("VK_KHR_incremental_present")
- VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
+ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
//@extension("VK_NVX_device_generated_commands")
- VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
-
- //@extension("VK_NVX_device_generated_commands")
- VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
-
- //@extension("VK_NVX_device_generated_commands")
- VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
-
- //@extension("VK_NVX_device_generated_commands")
- VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
-
- //@extension("VK_NVX_device_generated_commands")
- VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
-
- //@extension("VK_NVX_device_generated_commands")
- VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
+ VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
+ VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
+ VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
+ VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
+ VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
+ VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
}
enum VkSubpassContents {
@@ -939,7 +926,7 @@
@extension("VK_KHR_surface")
enum VkColorSpaceKHR {
VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000,
- VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001,
+ VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001,
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002,
VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003,
VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004,
@@ -1009,23 +996,23 @@
@extension("VK_NVX_device_generated_commands")
enum VkIndirectCommandsTokenTypeNVX {
- VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,
- VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,
- VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,
- VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,
- VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,
- VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,
- VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,
- VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,
+ VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,
+ VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,
+ VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,
+ VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,
+ VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,
+ VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,
+ VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,
+ VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,
}
@extension("VK_NVX_device_generated_commands")
enum VkObjectEntryTypeNVX {
- VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,
- VK_OBJECT_ENTRY_PIPELINE_NVX = 1,
- VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,
- VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,
- VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,
+ VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,
+ VK_OBJECT_ENTRY_PIPELINE_NVX = 1,
+ VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,
+ VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,
+ VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,
}
/////////////////
@@ -1080,8 +1067,6 @@
//@extension("VK_NVX_device_generated_commands")
VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
-
- //@extension("VK_NVX_device_generated_commands")
VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
}
@@ -1568,6 +1553,13 @@
//bitfield VkWin32SurfaceCreateFlagBitsKHR {
//}
+@extension("VK_ANDROID_native_buffer")
+type VkFlags VkSwapchainImageUsageFlagsANDROID
+@extension("VK_ANDROID_native_buffer")
+bitfield VkSwapchainImageUsageFlagBitsANDROID {
+ VK_SWAPCHAIN_IMAGE_USAGE_FLAGS_SHARED_BIT_ANDROID = 0x00000001,
+}
+
@extension("VK_EXT_debug_report")
type VkFlags VkDebugReportFlagsEXT
@extension("VK_EXT_debug_report")
@@ -1579,51 +1571,43 @@
VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
}
-@extension("VK_ANDROID_native_buffer")
-type VkFlags VkSwapchainImageUsageFlagsANDROID
-@extension("VK_ANDROID_native_buffer")
-bitfield VkSwapchainImageUsageFlagBitsANDROID {
- VK_SWAPCHAIN_IMAGE_USAGE_FLAGS_SHARED_BIT_ANDROID = 0x00000001,
-}
-
@extension("VK_NV_external_memory_capabilities")
type VkFlags VkExternalMemoryHandleTypeFlagsNV
@extension("VK_NV_external_memory_capabilities")
bitfield VkExternalMemoryHandleTypeFlagBitsNV {
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
}
@extension("VK_NV_external_memory_capabilities")
type VkFlags VkExternalMemoryFeatureFlagsNV
@extension("VK_NV_external_memory_capabilities")
bitfield VkExternalMemoryFeatureFlagBitsNV {
- VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
}
@extension("VK_NVX_device_generated_commands")
type VkFlags VkIndirectCommandsLayoutUsageFlagsNVX
@extension("VK_NVX_device_generated_commands")
bitfield VkIndirectCommandsLayoutUsageFlagBitsNVX {
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
}
@extension("VK_NVX_device_generated_commands")
type VkFlags VkObjectEntryUsageFlagsNVX
@extension("VK_NVX_device_generated_commands")
bitfield VkObjectEntryUsageFlagBitsNVX {
- VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
- VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
+ VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
+ VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
}
-
//////////////////
// Structures //
//////////////////
@@ -2931,6 +2915,13 @@
VkSwapchainImageUsageFlagsANDROID flags
}
+@extension("VK_ANDROID_native_buffer")
+class VkPhysicalDevicePresentationPropertiesANDROID {
+ VkStructureType sType
+ void* pNext
+ VkBool32 sharedImage
+}
+
@extension("VK_GOOGLE_display_timing")
class VkRefreshCycleDurationGOOGLE {
u64 minRefreshDuration
@@ -3026,6 +3017,57 @@
VkBuffer buffer
}
+@extension("VK_NV_external_memory_capabilities")
+class VkExternalImageFormatPropertiesNV {
+ VkImageFormatProperties imageFormatProperties
+ VkExternalMemoryFeatureFlagsNV externalMemoryFeatures
+ VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes
+ VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes
+}
+
+@extension("VK_NV_external_memory")
+class VkExternalMemoryImageCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsNV handleTypes
+}
+
+@extension("VK_NV_external_memory")
+class VkExportMemoryAllocateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsNV handleTypes
+}
+
+@extension("VK_NV_external_memory_win32")
+class VkImportMemoryWin32HandleInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsNV handleType
+ platform.HANDLE handle
+}
+
+@extension("VK_NV_external_memory_win32")
+class VkExportMemoryWin32HandleInfoNV {
+ VkStructureType sType
+ const void* pNext
+ const platform.SECURITY_ATTRIBUTES* pAttributes
+ platform.DWORD dwAccess
+}
+
+@extension("VK_NV_win32_keyed_mutex")
+class VkWin32KeyedMutexAcquireReleaseInfoNV {
+ VkStructureType sType
+ const void* pNext
+ u32 acquireCount
+ const VkDeviceMemory* pAcquireSyncs
+ const u64* pAcquireKeys
+ const u32* pAcquireTimeoutMilliseconds
+ u32 releaseCount
+ const VkDeviceMemory* pReleaseSyncs
+ const u64* pReleaseKeys
+}
+
@extension("VK_KHR_get_physical_device_properties2")
class VkPhysicalDeviceFeatures2KHR {
VkStructureType sType
@@ -3097,78 +3139,6 @@
VkImageTiling tiling
}
-@extension("VK_KHR_incremental_present")
-class VkRectLayerKHR {
- VkOffset2D offset
- VkExtent2D extent
- u32 layer
-}
-
-@extension("VK_KHR_incremental_present")
-class VkPresentRegionKHR {
- u32 rectangleCount
- const VkRectLayerKHR* pRectangles
-}
-
-@extension("VK_KHR_incremental_present")
-class VkPresentRegionsKHR {
- VkStructureType sType
- const void* pNext
- u32 swapchainCount
- const VkPresentRegionKHR* pRegions
-}
-
-@extension("VK_NV_external_memory_capabilities")
-class VkExternalImageFormatPropertiesNV {
- VkImageFormatProperties imageFormatProperties
- VkExternalMemoryFeatureFlagsNV externalMemoryFeatures
- VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes
- VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes
-}
-
-@extension("VK_NV_external_memory")
-class VkExternalMemoryImageCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsNV handleTypes
-}
-
-@extension("VK_NV_external_memory")
-class VkExportMemoryAllocateInfoNV {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsNV handleTypes
-}
-
-@extension("VK_NV_external_memory_win32")
-class VkImportMemoryWin32HandleInfoNV {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsNV handleType
- platform.HANDLE handle
-}
-
-@extension("VK_NV_external_memory_win32")
-class VkExportMemoryWin32HandleInfoNV {
- VkStructureType sType
- const void* pNext
- const platform.SECURITY_ATTRIBUTES* pAttributes
- u32 dwAccess
-}
-
-@extension("VK_NV_win32_keyed_mutex")
-class VkWin32KeyedMutexAcquireReleaseInfoNV {
- VkStructureType sType
- const void* pNext
- u32 acquireCount
- const VkDeviceMemory* pAcquireSyncs
- const u64* pAcquireKeys
- const u32* pAcquireTimeoutMilliseconds
- u32 releaseCount
- const VkDeviceMemory* pReleaseSyncs
- const u64* pReleaseKeys
-}
-
@extension("VK_EXT_validation_flags")
class VkValidationFlagsEXT {
VkStructureType sType
@@ -3303,7 +3273,44 @@
VkShaderStageFlags stageFlags
}
+@extension("VK_KHR_incremental_present")
+class VkRectLayerKHR {
+ VkOffset2D offset
+ VkExtent2D extent
+ u32 layer
+}
+@extension("VK_KHR_incremental_present")
+class VkPresentRegionKHR {
+ u32 rectangleCount
+ const VkRectLayerKHR* pRectangles
+}
+
+@extension("VK_KHR_incremental_present")
+class VkPresentRegionsKHR {
+ VkStructureType sType
+ const void* pNext
+ u32 swapchainCount
+ const VkPresentRegionKHR* pRegions
+}
+
+@extension("VK_EXT_hdr_metadata")
+class VkXYColorEXT {
+ f32 x
+ f32 y
+}
+
+@extension("VK_EXT_hdr_metadata")
+class VkHdrMetadataEXT {
+ VkXYColorEXT displayPrimaryRed
+ VkXYColorEXT displayPrimaryGreen
+ VkXYColorEXT displayPrimaryBlue
+ VkXYColorEXT whitePoint
+ f32 maxLuminance
+ f32 minLuminance
+ f32 maxContentLightLevel
+ f32 maxFrameAverageLightLevel
+}
////////////////
// Commands //
@@ -5977,6 +5984,50 @@
VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
}
+@extension("VK_AMD_draw_indirect_count")
+cmd void vkCmdDrawIndirectCountAMD(
+ VkCommandBuffer commandBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countBufferOffset,
+ u32 maxDrawCount,
+ u32 stride) {
+}
+
+@extension("VK_AMD_draw_indirect_count")
+cmd void vkCmdDrawIndexedIndirectCountAMD(
+ VkCommandBuffer commandBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countBufferOffset,
+ u32 maxDrawCount,
+ u32 stride) {
+}
+
+@extension("VK_NV_external_memory_capabilities")
+cmd VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkImageType type,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties) {
+ return ?
+}
+
+@extension("VK_NV_external_memory_win32")
+cmd VkResult vkGetMemoryWin32HandleNV(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagsNV handleType,
+ platform.HANDLE* pHandle) {
+ return ?
+}
+
@extension("VK_KHR_get_physical_device_properties2")
cmd void vkGetPhysicalDeviceFeatures2KHR(
VkPhysicalDevice physicalDevice,
@@ -6025,64 +6076,20 @@
VkSparseImageFormatProperties2KHR* pProperties) {
}
-@extension("VK_AMD_draw_indirect_count")
-cmd void vkCmdDrawIndirectCountAMD(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_AMD_draw_indirect_count")
-cmd void vkCmdDrawIndexedIndirectCountAMD(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_NV_external_memory_capabilities")
-cmd VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkImageType type,
- VkImageTiling tiling,
- VkImageUsageFlags usage,
- VkImageCreateFlags flags,
- VkExternalMemoryHandleTypeFlagsNV externalHandleType,
- VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties) {
- return ?
-}
-
-@extension("VK_NV_external_memory_win32")
-cmd VkResult vkGetMemoryWin32HandleNV(
- VkDevice device,
- VkDeviceMemory memory,
- VkExternalMemoryHandleTypeFlagsNV handleType,
- platform.HANDLE* pHandle) {
- return ?
-}
-
-@extension("VK_NV_external_memory_win32")
-cmd void vkCmdProcessCommandsNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd void vkCmdProcessCommandsNVX(
VkCommandBuffer commandBuffer,
const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo) {
}
-@extension("VK_NV_external_memory_win32")
-cmd void vkCmdReserveSpaceForCommandsNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd void vkCmdReserveSpaceForCommandsNVX(
VkCommandBuffer commandBuffer,
const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo) {
}
-@extension("VK_NV_external_memory_win32")
-cmd VkResult vkCreateIndirectCommandsLayoutNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd VkResult vkCreateIndirectCommandsLayoutNVX(
VkDevice device,
const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
@@ -6090,15 +6097,15 @@
return ?
}
-@extension("VK_NV_external_memory_win32")
-cmd void vkDestroyIndirectCommandsLayoutNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd void vkDestroyIndirectCommandsLayoutNVX(
VkDevice device,
VkIndirectCommandsLayoutNVX indirectCommandsLayout,
const VkAllocationCallbacks* pAllocator) {
}
-@extension("VK_NV_external_memory_win32")
-cmd VkResult vkCreateObjectTableNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd VkResult vkCreateObjectTableNVX(
VkDevice device,
const VkObjectTableCreateInfoNVX* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
@@ -6106,15 +6113,15 @@
return ?
}
-@extension("VK_NV_external_memory_win32")
-cmd void vkDestroyObjectTableNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd void vkDestroyObjectTableNVX(
VkDevice device,
VkObjectTableNVX objectTable,
const VkAllocationCallbacks* pAllocator) {
}
-@extension("VK_NV_external_memory_win32")
-cmd VkResult vkRegisterObjectsNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd VkResult vkRegisterObjectsNVX(
VkDevice device,
VkObjectTableNVX objectTable,
u32 objectCount,
@@ -6123,8 +6130,8 @@
return ?
}
-@extension("VK_NV_external_memory_win32")
-cmd VkResult vkUnregisterObjectsNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd VkResult vkUnregisterObjectsNVX(
VkDevice device,
VkObjectTableNVX objectTable,
u32 objectCount,
@@ -6133,13 +6140,21 @@
return ?
}
-@extension("VK_NV_external_memory_win32")
-cmd void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
+@extension("VK_NVX_device_generated_commands")
+cmd void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
VkPhysicalDevice physicalDevice,
VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
VkDeviceGeneratedCommandsLimitsNVX* pLimits) {
}
+@extension("VK_EXT_hdr_metadata")
+cmd void vkSetHdrMetadataEXT(
+ VkDevice device,
+ u32 swapchainCount,
+ const VkSwapchainKHR* pSwapchains,
+ const VkHdrMetadataEXT* pMetadata) {
+}
+
@extension("VK_KHR_shared_presentable_image")
cmd VkResult vkGetSwapchainStatusKHR(
VkDevice device,
@@ -6147,7 +6162,6 @@
return ?
}
-
////////////////
// Validation //
////////////////
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index d7c5a07..43a9a9c 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -37,12 +37,13 @@
* backwards-compatibility support is temporary, and will likely be removed in
* (along with all gralloc0 support) in a future release.
*/
-#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 6
+#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 7
#define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer"
#define VK_ANDROID_NATIVE_BUFFER_ENUM(type,id) ((type)(1000000000 + (1000 * (VK_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER - 1)) + (id)))
#define VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 0)
#define VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 1)
+#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 2)
typedef enum VkSwapchainImageUsageFlagBitsANDROID {
VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID = 0x00000001,
@@ -75,6 +76,13 @@
VkSwapchainImageUsageFlagsANDROID usage;
} VkSwapchainImageCreateInfoANDROID;
+typedef struct {
+ VkStructureType sType; // must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID
+ const void* pNext;
+
+ VkBool32 sharedImage;
+} VkPhysicalDevicePresentationPropertiesANDROID;
+
// -- DEPRECATED in SPEC_VERSION 6 --
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
// -- ADDED in SPEC_VERSION 6 --
diff --git a/vulkan/include/vulkan/vk_platform.h b/vulkan/include/vulkan/vk_platform.h
index c2232ec..2054447 100644
--- a/vulkan/include/vulkan/vk_platform.h
+++ b/vulkan/include/vulkan/vk_platform.h
@@ -53,7 +53,7 @@
#define VKAPI_PTR VKAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "Vulkan isn't supported for the 'armeabi' NDK ABI"
-#elif defined(__ANDROID__) && __ARM_ARCH >= 7 && __ARM_32BIT_STATE
+#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
@@ -94,7 +94,7 @@
// controls inclusion of the extension interfaces in vulkan.h.
#ifdef VK_USE_PLATFORM_ANDROID_KHR
-#include <android/native_window.h>
+struct ANativeWindow;
#endif
#ifdef VK_USE_PLATFORM_MIR_KHR
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 8d24aa7..43dba6e 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2015-2016 The Khronos Group Inc.
+** Copyright (c) 2015-2017 The Khronos Group Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -220,7 +220,6 @@
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
- VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
@@ -236,6 +235,7 @@
VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
+ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
@@ -3702,7 +3702,6 @@
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#define VK_KHR_android_surface 1
-#include <android/native_window.h>
#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface"
@@ -4154,52 +4153,6 @@
} VkDedicatedAllocationMemoryAllocateInfoNV;
-#define VK_GOOGLE_display_timing 1
-#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
-#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
-
-typedef struct VkRefreshCycleDurationGOOGLE {
- uint64_t refreshDuration;
-} VkRefreshCycleDurationGOOGLE;
-
-typedef struct VkPastPresentationTimingGOOGLE {
- uint32_t presentID;
- uint64_t desiredPresentTime;
- uint64_t actualPresentTime;
- uint64_t earliestPresentTime;
- uint64_t presentMargin;
-} VkPastPresentationTimingGOOGLE;
-
-typedef struct VkPresentTimeGOOGLE {
- uint32_t presentID;
- uint64_t desiredPresentTime;
-} VkPresentTimeGOOGLE;
-
-typedef struct VkPresentTimesInfoGOOGLE {
- VkStructureType sType;
- const void* pNext;
- uint32_t swapchainCount;
- const VkPresentTimeGOOGLE* pTimes;
-} VkPresentTimesInfoGOOGLE;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE(
- VkDevice device,
- VkSwapchainKHR swapchain,
- VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE(
- VkDevice device,
- VkSwapchainKHR swapchain,
- uint32_t* pPresentationTimingCount,
- VkPastPresentationTimingGOOGLE* pPresentationTimings);
-#endif
-
-
#define VK_AMD_draw_indirect_count 1
#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -4608,6 +4561,84 @@
VkDeviceGeneratedCommandsLimitsNVX* pLimits);
#endif
+#define VK_GOOGLE_display_timing 1
+#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
+#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
+
+typedef struct VkRefreshCycleDurationGOOGLE {
+ uint64_t refreshDuration;
+} VkRefreshCycleDurationGOOGLE;
+
+typedef struct VkPastPresentationTimingGOOGLE {
+ uint32_t presentID;
+ uint64_t desiredPresentTime;
+ uint64_t actualPresentTime;
+ uint64_t earliestPresentTime;
+ uint64_t presentMargin;
+} VkPastPresentationTimingGOOGLE;
+
+typedef struct VkPresentTimeGOOGLE {
+ uint32_t presentID;
+ uint64_t desiredPresentTime;
+} VkPresentTimeGOOGLE;
+
+typedef struct VkPresentTimesInfoGOOGLE {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t swapchainCount;
+ const VkPresentTimeGOOGLE* pTimes;
+} VkPresentTimesInfoGOOGLE;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ uint32_t* pPresentationTimingCount,
+ VkPastPresentationTimingGOOGLE* pPresentationTimings);
+#endif
+
+#define VK_EXT_hdr_metadata 1
+#define VK_EXT_HDR_METADATA_SPEC_VERSION 0
+#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
+
+typedef struct VkXYColorEXT {
+ float x;
+ float y;
+} VkXYColorEXT;
+
+typedef struct VkHdrMetadataEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkXYColorEXT displayPrimaryRed;
+ VkXYColorEXT displayPrimaryGreen;
+ VkXYColorEXT displayPrimaryBlue;
+ VkXYColorEXT whitePoint;
+ float maxLuminance;
+ float minLuminance;
+ float maxContentLightLevel;
+ float maxFrameAverageLightLevel;
+} VkHdrMetadataEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT(
+ VkDevice device,
+ uint32_t swapchainCount,
+ const VkSwapchainKHR* pSwapchains,
+ const VkHdrMetadataEXT* pMetadata);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index e3c44d2..4835a56 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -319,7 +319,7 @@
}
¶
ProcHook::Extension GetProcHookExtension(const char* name) {
- {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+ {{$exts := Strings (Macro "driver.KnownExtensions") | SplitOn "\n"}}
// clang-format off
{{range $e := $exts}}
if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}};
@@ -682,17 +682,29 @@
{{define "driver.InterceptedExtensions"}}
VK_ANDROID_native_buffer
VK_EXT_debug_report
+VK_EXT_hdr_metadata
+VK_GOOGLE_display_timing
VK_KHR_android_surface
VK_KHR_incremental_present
VK_KHR_surface
VK_KHR_swapchain
-VK_GOOGLE_display_timing
VK_KHR_shared_presentable_image
{{end}}
{{/*
------------------------------------------------------------------------------
+ Emits a list of extensions known to vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.KnownExtensions"}}
+{{Macro "driver.InterceptedExtensions"}}
+VK_KHR_get_physical_device_properties2
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
Emits true if an extension is intercepted by vulkan::driver.
------------------------------------------------------------------------------
*/}}
@@ -775,7 +787,7 @@
};
enum Extension {
- {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+ {{$exts := Strings (Macro "driver.KnownExtensions") | SplitOn "\n"}}
{{range $e := $exts}}
{{TrimPrefix "VK_" $e}},
{{end}}
@@ -964,7 +976,7 @@
{{else if eq $.Name "vkDestroyImage"}}true
{{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
-
+ {{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true
{{end}}
{{$ext := GetAnnotation $ "extension"}}
@@ -1121,14 +1133,17 @@
{{else if eq $ext "VK_KHR_wayland_surface"}}true
{{else if eq $ext "VK_KHR_mir_surface"}}true
{{else if eq $ext "VK_KHR_win32_surface"}}true
+ {{else if eq $ext "VK_NV_external_memory_win32"}}true
+ {{else if eq $ext "VK_NV_win32_keyed_mutex"}}true
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
- Reports whether an extension is implemented entirely by the loader,
- so drivers should not enumerate it.
+ Reports whether an extension has functions exported by the loader.
+ E.g. applications can directly link to an extension function.
+ Currently only support WSI extensions this way.
------------------------------------------------------------------------------
*/}}
{{define "IsExtensionExported"}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 32f777d..76aa176 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -29,6 +29,7 @@
#include <android/dlext.h>
#include <cutils/properties.h>
#include <ui/GraphicsEnv.h>
+#include <utils/Vector.h>
#include "driver.h"
#include "stubhal.h"
@@ -454,6 +455,7 @@
hook_extensions_.set(ext_bit);
break;
case ProcHook::EXTENSION_UNKNOWN:
+ case ProcHook::KHR_get_physical_device_properties2:
// HAL's extensions
break;
default:
@@ -469,15 +471,16 @@
break;
case ProcHook::KHR_incremental_present:
case ProcHook::GOOGLE_display_timing:
+ case ProcHook::KHR_shared_presentable_image:
hook_extensions_.set(ext_bit);
// return now as these extensions do not require HAL support
return;
+ case ProcHook::EXT_hdr_metadata:
+ hook_extensions_.set(ext_bit);
+ break;
case ProcHook::EXTENSION_UNKNOWN:
// HAL's extensions
break;
- case ProcHook::KHR_shared_presentable_image:
- // Exposed by HAL, but API surface is all in the loader
- break;
default:
ALOGW("Ignored invalid device extension %s", name);
return;
@@ -495,10 +498,6 @@
if (ext_bit == ProcHook::ANDROID_native_buffer)
hook_extensions_.set(ProcHook::KHR_swapchain);
- // Exposed by HAL, but API surface is all in the loader
- if (ext_bit == ProcHook::KHR_shared_presentable_image)
- hook_extensions_.set(ext_bit);
-
hal_extensions_.set(ext_bit);
}
@@ -731,19 +730,63 @@
return result;
}
+bool QueryPresentationProperties(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties)
+{
+ const InstanceData& data = GetData(physicalDevice);
+
+ // GPDP2 must be present and enabled on the instance.
+ if (!data.driver.GetPhysicalDeviceProperties2KHR)
+ return false;
+
+ // Request the android-specific presentation properties via GPDP2
+ VkPhysicalDeviceProperties2KHR properties = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+ presentation_properties,
+ {}
+ };
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ presentation_properties->sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID;
+#pragma clang diagnostic pop
+ presentation_properties->pNext = nullptr;
+ presentation_properties->sharedImage = VK_FALSE;
+
+ data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
+ &properties);
+
+ return true;
+}
+
VkResult EnumerateDeviceExtensionProperties(
VkPhysicalDevice physicalDevice,
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
const InstanceData& data = GetData(physicalDevice);
- static const std::array<VkExtensionProperties, 2> loader_extensions = {{
- // WSI extensions
- {VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
- VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION},
- {VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
- VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION},
- }};
+ // extensions that are unconditionally exposed by the loader
+ android::Vector<VkExtensionProperties> loader_extensions;
+ loader_extensions.push_back({
+ VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
+ VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
+ loader_extensions.push_back({
+ VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
+ VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
+ loader_extensions.push_back({
+ VK_EXT_HDR_METADATA_EXTENSION_NAME,
+ VK_EXT_HDR_METADATA_SPEC_VERSION});
+
+ // conditionally add shared_presentable_image if supportable
+ VkPhysicalDevicePresentationPropertiesANDROID presentation_properties;
+ if (QueryPresentationProperties(physicalDevice, &presentation_properties) &&
+ presentation_properties.sharedImage) {
+ loader_extensions.push_back({
+ VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
+ VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION});
+ }
// enumerate our extensions first
if (!pLayerName && pProperties) {
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 5383f59..7f8ae98 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -109,6 +109,10 @@
bool OpenHAL();
const VkAllocationCallbacks& GetDefaultAllocator();
+bool QueryPresentationProperties(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties);
+
// clang-format off
VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName);
VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName);
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 951ea6e..c4cb544 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -93,6 +93,14 @@
}
}
+VKAPI_ATTR void checkedSetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata) {
+ if (GetData(device).hook_extensions[ProcHook::EXT_hdr_metadata]) {
+ SetHdrMetadataEXT(device, swapchainCount, pSwapchains, pMetadata);
+ } else {
+ Logger(device).Err(device, "VK_EXT_hdr_metadata not enabled. vkSetHdrMetadataEXT not executed.");
+ }
+}
+
VKAPI_ATTR VkResult checkedGetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain) {
if (GetData(device).hook_extensions[ProcHook::KHR_shared_presentable_image]) {
return GetSwapchainStatusKHR(device, swapchain);
@@ -330,6 +338,13 @@
nullptr,
nullptr,
},
+ {
+ "vkSetHdrMetadataEXT",
+ ProcHook::DEVICE,
+ ProcHook::EXT_hdr_metadata,
+ reinterpret_cast<PFN_vkVoidFunction>(SetHdrMetadataEXT),
+ reinterpret_cast<PFN_vkVoidFunction>(checkedSetHdrMetadataEXT),
+ },
// clang-format on
};
@@ -349,12 +364,14 @@
// clang-format off
if (strcmp(name, "VK_ANDROID_native_buffer") == 0) return ProcHook::ANDROID_native_buffer;
if (strcmp(name, "VK_EXT_debug_report") == 0) return ProcHook::EXT_debug_report;
+ if (strcmp(name, "VK_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata;
+ if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
- if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
+ if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
}
@@ -393,6 +410,7 @@
INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceProperties2KHR);
// clang-format on
return success;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 95c70f8..c9dba78 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -35,12 +35,14 @@
enum Extension {
ANDROID_native_buffer,
EXT_debug_report,
+ EXT_hdr_metadata,
+ GOOGLE_display_timing,
KHR_android_surface,
KHR_incremental_present,
KHR_surface,
KHR_swapchain,
- GOOGLE_display_timing,
KHR_shared_presentable_image,
+ KHR_get_physical_device_properties2,
EXTENSION_CORE, // valid bit
EXTENSION_COUNT,
@@ -66,6 +68,7 @@
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+ PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR;
// clang-format on
};
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 9630ac9..31f8796 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -542,26 +542,32 @@
}
VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
+VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
VkSurfaceKHR /*surface*/,
uint32_t* count,
VkPresentModeKHR* modes) {
- const VkPresentModeKHR kModes[] = {
- VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
- // TODO(chrisforbes): should only expose this if the driver can.
- // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
- // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
- };
- const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
+ android::Vector<VkPresentModeKHR> present_modes;
+ present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+ present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+
+ VkPhysicalDevicePresentationPropertiesANDROID present_properties;
+ if (QueryPresentationProperties(pdev, &present_properties)) {
+ if (present_properties.sharedImage) {
+ present_modes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR);
+ present_modes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR);
+ }
+ }
+
+ uint32_t num_modes = uint32_t(present_modes.size());
VkResult result = VK_SUCCESS;
if (modes) {
- if (*count < kNumModes)
+ if (*count < num_modes)
result = VK_INCOMPLETE;
- *count = std::min(*count, kNumModes);
- std::copy(kModes, kModes + *count, modes);
+ *count = std::min(*count, num_modes);
+ std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes);
} else {
- *count = kNumModes;
+ *count = num_modes;
}
return result;
}
@@ -1351,5 +1357,18 @@
return result;
}
+VKAPI_ATTR void SetHdrMetadataEXT(
+ VkDevice device,
+ uint32_t swapchainCount,
+ const VkSwapchainKHR* pSwapchains,
+ const VkHdrMetadataEXT* pHdrMetadataEXTs) {
+ // TODO: courtneygo: implement actual function
+ (void)device;
+ (void)swapchainCount;
+ (void)pSwapchains;
+ (void)pHdrMetadataEXTs;
+ return;
+}
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index 91d7219..4d9f18f 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -37,6 +37,7 @@
VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
VKAPI_ATTR VkResult GetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain);
+VKAPI_ATTR void SetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pHdrMetadataEXTs);
// clang-format on
} // namespace driver