Merge "Add feature tag android.hardware.vr.headtracking."
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 58b9d2c..0d5652f 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -45,10 +45,15 @@
using android::base::StringPrintf;
using android::base::EndsWith;
+using android::base::unique_fd;
namespace android {
namespace installd {
+static unique_fd invalid_unique_fd() {
+ return unique_fd(-1);
+}
+
static const char* parse_null(const char* arg) {
if (strcmp(arg, "!") == 0) {
return nullptr;
@@ -58,7 +63,7 @@
}
static bool clear_profile(const std::string& profile) {
- base::unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
if (ufd.get() < 0) {
if (errno != ENOENT) {
PLOG(WARNING) << "Could not open profile " << profile;
@@ -467,18 +472,10 @@
}
}
-static void close_all_fds(const std::vector<fd_t>& fds, const char* description) {
- for (size_t i = 0; i < fds.size(); i++) {
- if (close(fds[i]) != 0) {
- PLOG(WARNING) << "Failed to close fd for " << description << " at index " << i;
- }
- }
-}
-
-static fd_t open_profile_dir(const std::string& profile_dir) {
- fd_t profile_dir_fd = TEMP_FAILURE_RETRY(open(profile_dir.c_str(),
- O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW));
- if (profile_dir_fd < 0) {
+static unique_fd open_profile_dir(const std::string& profile_dir) {
+ unique_fd profile_dir_fd(TEMP_FAILURE_RETRY(open(profile_dir.c_str(),
+ O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW)));
+ if (profile_dir_fd.get() < 0) {
// In a multi-user environment, these directories can be created at
// different points and it's possible we'll attempt to open a profile
// dir before it exists.
@@ -489,66 +486,61 @@
return profile_dir_fd;
}
-static fd_t open_primary_profile_file_from_dir(const std::string& profile_dir, mode_t open_mode) {
- fd_t profile_dir_fd = open_profile_dir(profile_dir);
- if (profile_dir_fd < 0) {
- return -1;
+static unique_fd open_primary_profile_file_from_dir(const std::string& profile_dir,
+ mode_t open_mode) {
+ unique_fd profile_dir_fd = open_profile_dir(profile_dir);
+ if (profile_dir_fd.get() < 0) {
+ return invalid_unique_fd();
}
- fd_t profile_fd = -1;
std::string profile_file = create_primary_profile(profile_dir);
-
- profile_fd = TEMP_FAILURE_RETRY(open(profile_file.c_str(), open_mode | O_NOFOLLOW, 0600));
+ unique_fd profile_fd(TEMP_FAILURE_RETRY(open(profile_file.c_str(),
+ open_mode | O_NOFOLLOW, 0600)));
if (profile_fd == -1) {
// It's not an error if the profile file does not exist.
if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir;
+ PLOG(ERROR) << "Failed to open profile : " << profile_file;
}
}
- // TODO(calin): use AutoCloseFD instead of closing the fd manually.
- if (close(profile_dir_fd) != 0) {
- PLOG(WARNING) << "Could not close profile dir " << profile_dir;
- }
return profile_fd;
}
-static fd_t open_primary_profile_file(userid_t user, const std::string& pkgname) {
+static unique_fd open_primary_profile_file(userid_t user, const std::string& pkgname) {
std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
return open_primary_profile_file_from_dir(profile_dir, O_RDONLY);
}
-static fd_t open_reference_profile(uid_t uid, const std::string& pkgname, bool read_write) {
+static unique_fd open_reference_profile(uid_t uid, const std::string& pkgname, bool read_write) {
std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY;
- fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
- if (fd < 0) {
- return -1;
+ unique_fd fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
+ if (fd.get() < 0) {
+ return invalid_unique_fd();
}
if (read_write) {
// Fix the owner.
- if (fchown(fd, uid, uid) < 0) {
- close(fd);
- return -1;
+ if (fchown(fd.get(), uid, uid) < 0) {
+ return invalid_unique_fd();
}
}
return fd;
}
static void open_profile_files(uid_t uid, const std::string& pkgname,
- /*out*/ std::vector<fd_t>* profiles_fd, /*out*/ fd_t* reference_profile_fd) {
+ /*out*/ std::vector<unique_fd>* profiles_fd, /*out*/ unique_fd* reference_profile_fd) {
// Open the reference profile in read-write mode as profman might need to save the merge.
*reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
- if (*reference_profile_fd < 0) {
+ if (reference_profile_fd->get() < 0) {
// We can't access the reference profile file.
return;
}
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
- fd_t profile_fd = open_primary_profile_file(user, pkgname);
+ unique_fd profile_fd = open_primary_profile_file(user, pkgname);
// Add to the lists only if both fds are valid.
- if (profile_fd >= 0) {
- profiles_fd->push_back(profile_fd);
+ if (profile_fd.get() >= 0) {
+ profiles_fd->push_back(std::move(profile_fd));
}
}
}
@@ -580,18 +572,19 @@
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-static void run_profman_merge(const std::vector<fd_t>& profiles_fd, fd_t reference_profile_fd) {
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd) {
static const size_t MAX_INT_LEN = 32;
static const char* PROFMAN_BIN = "/system/bin/profman";
std::vector<std::string> profile_args(profiles_fd.size());
char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
for (size_t k = 0; k < profiles_fd.size(); k++) {
- sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k]);
+ sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k].get());
profile_args[k].assign(profile_buf);
}
char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
- sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd);
+ sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd.get());
// program name, reference profile fd, the final NULL and the profile fds
const char* argv[3 + profiles_fd.size()];
@@ -615,16 +608,12 @@
// If the return value is true all the current profiles would have been merged into
// the reference profiles accessible with open_reference_profile().
bool analyse_profiles(uid_t uid, const std::string& pkgname) {
- std::vector<fd_t> profiles_fd;
- fd_t reference_profile_fd = -1;
+ std::vector<unique_fd> profiles_fd;
+ unique_fd reference_profile_fd;
open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
- if (profiles_fd.empty() || (reference_profile_fd == -1)) {
+ if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
// Skip profile guided compilation because no profiles were found.
// Or if the reference profile info couldn't be opened.
- close_all_fds(profiles_fd, "profiles_fd");
- if ((reference_profile_fd != - 1) && (close(reference_profile_fd) != 0)) {
- PLOG(WARNING) << "Failed to close fd for reference profile";
- }
return false;
}
@@ -679,10 +668,7 @@
break;
}
}
- close_all_fds(profiles_fd, "profiles_fd");
- if (close(reference_profile_fd) != 0) {
- PLOG(WARNING) << "Failed to close fd for reference profile";
- }
+
if (should_clear_current_profiles) {
clear_current_profiles(pkgname);
}
@@ -692,28 +678,28 @@
return need_to_compile;
}
-static void run_profman_dump(const std::vector<fd_t>& profile_fds,
- fd_t reference_profile_fd,
+static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
const std::vector<std::string>& dex_locations,
- const std::vector<fd_t>& apk_fds,
- fd_t output_fd) {
+ const std::vector<unique_fd>& apk_fds,
+ const unique_fd& output_fd) {
std::vector<std::string> profman_args;
static const char* PROFMAN_BIN = "/system/bin/profman";
profman_args.push_back(PROFMAN_BIN);
profman_args.push_back("--dump-only");
- profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd));
+ profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
if (reference_profile_fd != -1) {
profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
- reference_profile_fd));
+ reference_profile_fd.get()));
}
- for (fd_t profile_fd : profile_fds) {
- profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fd));
+ for (size_t i = 0; i < profile_fds.size(); i++) {
+ profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
}
for (const std::string& dex_location : dex_locations) {
profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
}
- for (fd_t apk_fd : apk_fds) {
- profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fd));
+ for (size_t i = 0; i < apk_fds.size(); i++) {
+ profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
}
const char **argv = new const char*[profman_args.size() + 1];
size_t i = 0;
@@ -739,13 +725,13 @@
}
bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
- std::vector<fd_t> profile_fds;
- fd_t reference_profile_fd = -1;
+ std::vector<unique_fd> profile_fds;
+ unique_fd reference_profile_fd;
std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
- const bool has_reference_profile = (reference_profile_fd != -1);
+ const bool has_reference_profile = (reference_profile_fd.get() != -1);
const bool has_profiles = !profile_fds.empty();
if (!has_reference_profile && !has_profiles) {
@@ -753,23 +739,23 @@
return false;
}
- fd_t output_fd = open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644);
+ unique_fd output_fd(open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
return false;
}
std::vector<std::string> code_full_paths = base::Split(code_paths, ";");
std::vector<std::string> dex_locations;
- std::vector<fd_t> apk_fds;
+ std::vector<unique_fd> apk_fds;
for (const std::string& code_full_path : code_full_paths) {
const char* full_path = code_full_path.c_str();
- fd_t apk_fd = open(full_path, O_RDONLY | O_NOFOLLOW);
+ unique_fd apk_fd(open(full_path, O_RDONLY | O_NOFOLLOW));
if (apk_fd == -1) {
ALOGE("installd cannot open '%s'\n", full_path);
return false;
}
dex_locations.push_back(get_location_from_path(full_path));
- apk_fds.push_back(apk_fd);
+ apk_fds.push_back(std::move(apk_fd));
}
pid_t pid = fork();
@@ -781,11 +767,6 @@
exit(68); /* only get here on exec failure */
}
/* parent */
- close_all_fds(apk_fds, "apk_fds");
- close_all_fds(profile_fds, "profile_fds");
- if (close(reference_profile_fd) != 0) {
- PLOG(WARNING) << "Failed to close fd for reference profile";
- }
int return_code = wait_child(pid);
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "profman failed for package " << pkgname << ": "
@@ -1053,17 +1034,17 @@
// Creates the dexopt swap file if necessary and return its fd.
// Returns -1 if there's no need for a swap or in case of errors.
-base::unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
if (!ShouldUseSwapFileForDexopt()) {
- return base::unique_fd();
+ return invalid_unique_fd();
}
// Make sure there really is enough space.
char swap_file_name[PKG_PATH_MAX];
strcpy(swap_file_name, out_oat_path);
if (!add_extension_to_file_name(swap_file_name, ".swap")) {
- return base::unique_fd();
+ return invalid_unique_fd();
}
- base::unique_fd swap_fd(open_output_file(
+ unique_fd swap_fd(open_output_file(
swap_file_name, /*recreate*/true, /*permissions*/0600));
if (swap_fd.get() < 0) {
// Could not create swap file. Optimistically go on and hope that we can compile
@@ -1088,8 +1069,9 @@
if (profile_guided && !is_secondary_dex && !is_public && (pkgname[0] != '*')) {
// Open reference profile in read only mode as dex2oat does not get write permissions.
const std::string pkgname_str(pkgname);
+ unique_fd profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
return Dex2oatFileWrapper(
- open_reference_profile(uid, pkgname, /*read_write*/ false),
+ profile_fd.release(),
[pkgname_str]() {
clear_reference_profile(pkgname_str.c_str());
});
@@ -1430,7 +1412,7 @@
}
// Open the input file.
- base::unique_fd input_fd(open(dex_path, O_RDONLY, 0));
+ unique_fd input_fd(open(dex_path, O_RDONLY, 0));
if (input_fd.get() < 0) {
ALOGE("installd cannot open '%s' for input during dexopt\n", dex_path);
return -1;
@@ -1453,7 +1435,7 @@
}
// Create a swap file if necessary.
- base::unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
+ unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
// Create the app image file if needed.
Dex2oatFileWrapper image_fd =
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index fab4d94..df6d176 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -32,8 +32,6 @@
static constexpr int DEX2OAT_FOR_RELOCATION = 4;
static constexpr int PATCHOAT_FOR_RELOCATION = 5;
-typedef int fd_t;
-
bool clear_reference_profile(const std::string& pkgname);
bool clear_current_profile(const std::string& pkgname, userid_t user);
bool clear_current_profiles(const std::string& pkgname);
diff --git a/cmds/vr/pose/Android.mk b/cmds/vr/pose/Android.mk
index 1657551..de92b5b 100644
--- a/cmds/vr/pose/Android.mk
+++ b/cmds/vr/pose/Android.mk
@@ -33,9 +33,3 @@
LOCAL_MODULE := pose
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
-
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-ALL_DEFAULT_INSTALLED_MODULES += pose
-all_modules: pose
-endif
-
diff --git a/cmds/vr/vrscreencap/Android.mk b/cmds/vr/vrscreencap/Android.mk
index 2fa9155..bd0b224 100644
--- a/cmds/vr/vrscreencap/Android.mk
+++ b/cmds/vr/vrscreencap/Android.mk
@@ -21,8 +21,3 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
-
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-ALL_DEFAULT_INSTALLED_MODULES += vrscreencap
-all_modules: vrscreencap
-endif
diff --git a/include/binder/HalToken.h b/include/binder/HalToken.h
deleted file mode 100644
index ce97c78..0000000
--- a/include/binder/HalToken.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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_HALTOKEN_H
-#define ANDROID_HALTOKEN_H
-
-#include <binder/Parcel.h>
-#include <hidl/HidlSupport.h>
-
-/**
- * Hybrid Interfaces
- * =================
- *
- * A hybrid interface is a binder interface that
- * 1. is implemented both traditionally and as a wrapper around a hidl
- * interface, and allows querying whether the underlying instance comes from
- * a hidl interface or not; and
- * 2. allows efficient calls to a hidl interface (if the underlying instance
- * comes from a hidl interface) by automatically creating the wrapper in the
- * process that calls it.
- *
- * Terminology:
- * - `HalToken`: The type for a "token" of a hidl interface. This is defined to
- * be compatible with `ITokenManager.hal`.
- * - `HInterface`: The base type for a hidl interface. Currently, it is defined
- * as `::android::hidl::base::V1_0::IBase`.
- * - `HALINTERFACE`: The hidl interface that will be sent through binders.
- * - `INTERFACE`: The binder interface that will be the wrapper of
- * `HALINTERFACE`. `INTERFACE` is supposed to be somewhat similar to
- * `HALINTERFACE`.
- *
- * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
- * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
- * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
- * definition of `IFoo`. The usage is
- * DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
- * inside the body of `IFoo`.
- * 2. Create a converter class that derives from
- * `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
- * 3. Add the following constructor in `H2BFoo` that call the corresponding
- * constructors in `H2BConverter`:
- * H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
- * Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
- * are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
- * line can be copied into `H2BFoo`.
- * 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
- * protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
- * instance. (There is also a public function named `getHalInterface()` that
- * returns `mBase`.)
- * 5. Create a hardware proxy class that derives from
- * `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
- * deviate. See step 8 below.)
- * 6. Add the following constructor to `HpFoo`:
- * HpFoo(const sp<IBinder>& base): PBase(base) {}
- * Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
- * equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
- * copied verbatim into `HpFoo`.
- * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
- * `getHalInterface` to the protected member `mBase`,
- * which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
- * type `IFoo`. (There is also a public function named `getBaseInterface()`
- * that returns `mBase`.)
- * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
- * `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
- * exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
- * An example usage is
- * IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
- *
- * `GETTOKEN` Template Argument
- * ============================
- *
- * Following the instructions above, `H2BConverter` and `HpInterface` would use
- * `transact()` to send over tokens, with `code` (the first argument of
- * `transact()`) equal to a 4-byte value of '_GTK'. If this value clashes with
- * other values already in use in the `Bp` class, it can be changed by supplying
- * the last optional template argument to `H2BConverter` and `HpInterface`.
- *
- */
-
-namespace android {
-
-typedef uint64_t HalToken;
-typedef ::android::hidl::base::V1_0::IBase HInterface;
-
-sp<HInterface> retrieveHalInterface(const HalToken& token);
-bool createHalToken(const sp<HInterface>& interface, HalToken* token);
-bool deleteHalToken(const HalToken& token);
-
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN = '_GTK'>
-class H2BConverter : public BNINTERFACE {
-public:
- typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
- typedef INTERFACE BaseInterface;
- typedef HINTERFACE HalInterface;
- static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
-
- H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
- virtual status_t onTransact(uint32_t code,
- const Parcel& data, Parcel* reply, uint32_t flags = 0);
- sp<HalInterface> getHalInterface() override { return mBase; }
- HalInterface* getBaseInterface() { return mBase.get(); }
-
-protected:
- sp<HalInterface> mBase;
-};
-
-template <
- typename BPINTERFACE,
- typename CONVERTER,
- uint32_t GETTOKEN = '_GTK'>
-class HpInterface : public CONVERTER::BaseInterface {
-public:
- typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
- typedef typename CONVERTER::BaseInterface BaseInterface;
- typedef typename CONVERTER::HalInterface HalInterface;
- static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
-
- explicit HpInterface(const sp<IBinder>& impl);
- sp<HalInterface> getHalInterface() override { return mHal; }
- BaseInterface* getBaseInterface() { return mBase.get(); }
-
-protected:
- sp<IBinder> mImpl;
- sp<BaseInterface> mBase;
- sp<HalInterface> mHal;
- IBinder* onAsBinder() override { return mImpl.get(); }
-};
-
-// ----------------------------------------------------------------------
-
-#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL) \
- static const ::android::String16 descriptor; \
- static ::android::sp<I##INTERFACE> asInterface( \
- const ::android::sp<::android::IBinder>& obj); \
- virtual const ::android::String16& getInterfaceDescriptor() const; \
- I##INTERFACE(); \
- virtual ~I##INTERFACE(); \
- virtual sp<HAL> getHalInterface(); \
-
-
-#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME) \
- const ::android::String16 I##INTERFACE::descriptor(NAME); \
- const ::android::String16& \
- I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
- const ::android::sp<::android::IBinder>& obj) \
- { \
- ::android::sp<I##INTERFACE> intr; \
- if (obj != NULL) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
- if (intr == NULL) { \
- intr = new Hp##INTERFACE(obj); \
- } \
- } \
- return intr; \
- } \
- I##INTERFACE::I##INTERFACE() { } \
- I##INTERFACE::~I##INTERFACE() { } \
- sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; } \
-
-// ----------------------------------------------------------------------
-
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
- onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- if (code == GET_HAL_TOKEN) {
- HalToken token;
- bool result;
- result = createHalToken(mBase, &token);
- if (!result) {
- ALOGE("H2BConverter: Failed to create HAL token.");
- }
- reply->writeBool(result);
- reply->writeUint64(token);
- return NO_ERROR;
- }
- return BNINTERFACE::onTransact(code, data, reply, flags);
-}
-
-template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
-HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
- const sp<IBinder>& impl) : mImpl(impl) {
- Parcel data, reply;
- data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
- if (impl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
- bool tokenCreated = reply.readBool();
- HalToken token = reply.readUint64();
- if (!tokenCreated) {
- ALOGE("HpInterface: Sender failed to create HAL token.");
- mBase = new BPINTERFACE(impl);
- } else {
- sp<HInterface> hInterface = retrieveHalInterface(token);
- deleteHalToken(token);
- if (hInterface != nullptr) {
- mHal = static_cast<HalInterface*>(hInterface.get());
- mBase = new CONVERTER(mHal);
- } else {
- ALOGE("HpInterface: Cannot retrieve HAL interface from token.");
- mBase = new BPINTERFACE(impl);
- }
- }
- } else {
- mBase = new BPINTERFACE(impl);
- }
-}
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_HALTOKEN_H
diff --git a/include/gui/BufferQueueDefs.h b/include/gui/BufferQueueDefs.h
index 83e9580..ffafb49 100644
--- a/include/gui/BufferQueueDefs.h
+++ b/include/gui/BufferQueueDefs.h
@@ -18,16 +18,12 @@
#define ANDROID_GUI_BUFFERQUEUECOREDEFS_H
#include <gui/BufferSlot.h>
+#include <ui/BufferQueueDefs.h>
namespace android {
class BufferQueueCore;
namespace BufferQueueDefs {
- // BufferQueue will keep track of at most this value of buffers.
- // Attempts at runtime to increase the number of buffers past this
- // will fail.
- enum { NUM_BUFFER_SLOTS = 64 };
-
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} // namespace BufferQueueDefs
} // namespace android
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 258cd2f..5810335 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -32,12 +32,17 @@
#include <gui/FrameTimestamps.h>
+#include <hidl/HybridInterface.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
namespace android {
// ----------------------------------------------------------------------------
class IProducerListener;
class NativeHandle;
class Surface;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+ HGraphicBufferProducer;
/*
* This class defines the Binder IPC interface for the producer side of
@@ -56,7 +61,7 @@
class IGraphicBufferProducer : public IInterface
{
public:
- DECLARE_META_INTERFACE(GraphicBufferProducer)
+ DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer)
enum {
// A flag returned by dequeueBuffer when the client needs to call
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/include/gui/bufferqueue/1.0/B2HProducerListener.h
new file mode 100644
index 0000000..fa6c2d9
--- /dev/null
+++ b/include/gui/bufferqueue/1.0/B2HProducerListener.h
@@ -0,0 +1,66 @@
+/*
+ * 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 ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener
+ HProducerListener;
+
+typedef ::android::IProducerListener
+ BProducerListener;
+
+struct B2HProducerListener : public HProducerListener {
+ sp<BProducerListener> mBase;
+ B2HProducerListener(sp<BProducerListener> const& base);
+ Return<void> onBufferReleased() override;
+ Return<bool> needsReleaseNotify() override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace omx
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
new file mode 100644
index 0000000..93c452a
--- /dev/null
+++ b/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -0,0 +1,106 @@
+/*
+ * 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 ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/Binder.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+
+#include <hidl/HybridInterface.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::media::V1_0::AnwBuffer;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+ HGraphicBufferProducer;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener
+ HProducerListener;
+
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+using ::android::BnGraphicBufferProducer;
+using ::android::IProducerListener;
+
+struct H2BGraphicBufferProducer : public ::android::H2BConverter<
+ HGraphicBufferProducer,
+ BGraphicBufferProducer,
+ BnGraphicBufferProducer> {
+ H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+
+ status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+ status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
+ status_t setAsyncMode(bool async) override;
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+ uint32_t h, ::android::PixelFormat format, uint32_t usage,
+ FrameEventHistoryDelta* outTimestamps) override;
+ status_t detachBuffer(int slot) override;
+ status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
+ override;
+ status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer)
+ override;
+ status_t queueBuffer(int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) override;
+ status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
+ int query(int what, int* value) override;
+ status_t connect(const sp<IProducerListener>& listener, int api,
+ bool producerControlledByApp, QueueBufferOutput* output) override;
+ status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api)
+ override;
+ status_t setSidebandStream(const sp<NativeHandle>& stream) override;
+ void allocateBuffers(uint32_t width, uint32_t height,
+ ::android::PixelFormat format, uint32_t usage) override;
+ status_t allowAllocation(bool allow) override;
+ status_t setGenerationNumber(uint32_t generationNumber) override;
+ String8 getConsumerName() const override;
+ status_t setSharedBufferMode(bool sharedBufferMode) override;
+ status_t setAutoRefresh(bool autoRefresh) override;
+ status_t setDequeueTimeout(nsecs_t timeout) override;
+ status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
+ status_t getUniqueId(uint64_t* outId) const override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
diff --git a/include/ui/BufferQueueDefs.h b/include/ui/BufferQueueDefs.h
new file mode 100644
index 0000000..56de181
--- /dev/null
+++ b/include/ui/BufferQueueDefs.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_BUFFERQUEUEDEFS_H
+#define ANDROID_UI_BUFFERQUEUEDEFS_H
+
+namespace android {
+ namespace BufferQueueDefs {
+ // BufferQueue will keep track of at most this value of buffers.
+ // Attempts at runtime to increase the number of buffers past this
+ // will fail.
+ static constexpr int NUM_BUFFER_SLOTS = 64;
+ } // namespace BufferQueueDefs
+} // namespace android
+
+#endif
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2cb44eb..93b8684 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -34,7 +34,6 @@
"IResultReceiver.cpp",
"IServiceManager.cpp",
"IShellCallback.cpp",
- "HalToken.cpp",
"MemoryBase.cpp",
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
@@ -66,8 +65,6 @@
"liblog",
"libcutils",
"libutils",
- "libhidlbase",
- "android.hidl.token@1.0",
],
export_shared_lib_headers: [
"libbase",
diff --git a/libs/binder/HalToken.cpp b/libs/binder/HalToken.cpp
deleted file mode 100644
index 6e71a52..0000000
--- a/libs/binder/HalToken.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2005 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 "HalToken"
-
-#include <utils/Log.h>
-#include <binder/HalToken.h>
-
-#include <android/hidl/token/1.0/ITokenManager.h>
-
-namespace android {
-
-using ::android::hidl::token::V1_0::ITokenManager;
-
-sp<ITokenManager> gTokenManager = nullptr;
-
-ITokenManager* getTokenManager() {
- if (gTokenManager != nullptr) {
- return gTokenManager.get();
- }
- gTokenManager = ITokenManager::getService();
- if (gTokenManager == nullptr) {
- ALOGE("Cannot retrieve TokenManager.");
- }
- return gTokenManager.get();
-}
-
-sp<HInterface> retrieveHalInterface(const HalToken& token) {
- auto transaction = getTokenManager()->get(token);
- if (!transaction.isOk()) {
- ALOGE("getHalInterface: Cannot obtain interface from token.");
- return nullptr;
- }
- return static_cast<sp<HInterface> >(transaction);
-}
-
-bool createHalToken(const sp<HInterface>& interface, HalToken* token) {
- auto transaction = getTokenManager()->createToken(interface);
- if (!transaction.isOk()) {
- ALOGE("createHalToken: Cannot create token from interface.");
- return false;
- }
- *token = static_cast<HalToken>(transaction);
- return true;
-}
-
-bool deleteHalToken(const HalToken& token) {
- auto transaction = getTokenManager()->unregister(token);
- if (!transaction.isOk()) {
- ALOGE("deleteHalToken: Cannot unregister hal token.");
- return false;
- }
- return true;
-}
-
-}; // namespace android
-
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a1b4abc..5f5fb91 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -41,6 +41,15 @@
// We are aware of the risks inherent in comparing floats for equality
"-Wno-float-equal",
+ // Pure abstract classes trigger this warning
+ "-Wno-weak-vtables",
+
+ // Allow four-character integer literals
+ "-Wno-four-char-constants",
+
+ // Allow documentation warnings
+ "-Wno-documentation",
+
"-DDEBUG_ONLY_CODE=0",
],
@@ -88,6 +97,8 @@
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
"view/Surface.cpp",
+ "bufferqueue/1.0/B2HProducerListener.cpp",
+ "bufferqueue/1.0/H2BGraphicBufferProducer.cpp"
],
shared_libs: [
@@ -100,9 +111,18 @@
"libutils",
"libnativewindow",
"liblog",
+ "libhidlbase",
+ "android.hidl.base@1.0",
+ "android.hidl.token@1.0-utils",
+ "android.hardware.graphics.bufferqueue@1.0",
],
- export_shared_lib_headers: ["libbinder", "libui"],
+ export_shared_lib_headers: [
+ "libbinder",
+ "libui",
+ "android.hidl.token@1.0-utils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ ],
}
subdirs = ["tests"]
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index abdf649..74117c8 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -30,9 +30,14 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+
namespace android {
// ----------------------------------------------------------------------------
+using ::android::hardware::graphics::bufferqueue::V1_0::utils::
+ H2BGraphicBufferProducer;
+
enum {
REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
DEQUEUE_BUFFER,
@@ -485,7 +490,123 @@
// translation unit (see clang warning -Wweak-vtables)
BpGraphicBufferProducer::~BpGraphicBufferProducer() {}
-IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
+class HpGraphicBufferProducer : public HpInterface<
+ BpGraphicBufferProducer, H2BGraphicBufferProducer> {
+public:
+ HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
+
+ status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
+ return mBase->requestBuffer(slot, buf);
+ }
+
+ status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override {
+ return mBase->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+ }
+
+ status_t setAsyncMode(bool async) override {
+ return mBase->setAsyncMode(async);
+ }
+
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage,
+ FrameEventHistoryDelta* outTimestamps) override {
+ return mBase->dequeueBuffer(
+ slot, fence, w, h, format, usage, outTimestamps);
+ }
+
+ status_t detachBuffer(int slot) override {
+ return mBase->detachBuffer(slot);
+ }
+
+ status_t detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
+ return mBase->detachNextBuffer(outBuffer, outFence);
+ }
+
+ status_t attachBuffer(
+ int* outSlot, const sp<GraphicBuffer>& buffer) override {
+ return mBase->attachBuffer(outSlot, buffer);
+ }
+
+ status_t queueBuffer(
+ int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) override {
+ return mBase->queueBuffer(slot, input, output);
+ }
+
+ status_t cancelBuffer(int slot, const sp<Fence>& fence) override {
+ return mBase->cancelBuffer(slot, fence);
+ }
+
+ int query(int what, int* value) override {
+ return mBase->query(what, value);
+ }
+
+ status_t connect(
+ const sp<IProducerListener>& listener,
+ int api, bool producerControlledByApp,
+ QueueBufferOutput* output) override {
+ return mBase->connect(listener, api, producerControlledByApp, output);
+ }
+
+ status_t disconnect(
+ int api, DisconnectMode mode = DisconnectMode::Api) override {
+ return mBase->disconnect(api, mode);
+ }
+
+ status_t setSidebandStream(const sp<NativeHandle>& stream) override {
+ return mBase->setSidebandStream(stream);
+ }
+
+ void allocateBuffers(uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t usage) override {
+ return mBase->allocateBuffers(width, height, format, usage);
+ }
+
+ status_t allowAllocation(bool allow) override {
+ return mBase->allowAllocation(allow);
+ }
+
+ status_t setGenerationNumber(uint32_t generationNumber) override {
+ return mBase->setGenerationNumber(generationNumber);
+ }
+
+ String8 getConsumerName() const override {
+ return mBase->getConsumerName();
+ }
+
+ status_t setSharedBufferMode(bool sharedBufferMode) override {
+ return mBase->setSharedBufferMode(sharedBufferMode);
+ }
+
+ status_t setAutoRefresh(bool autoRefresh) override {
+ return mBase->setAutoRefresh(autoRefresh);
+ }
+
+ status_t setDequeueTimeout(nsecs_t timeout) override {
+ return mBase->setDequeueTimeout(timeout);
+ }
+
+ status_t getLastQueuedBuffer(
+ sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence,
+ float outTransformMatrix[16]) override {
+ return mBase->getLastQueuedBuffer(
+ outBuffer, outFence, outTransformMatrix);
+ }
+
+ void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override {
+ return mBase->getFrameTimestamps(outDelta);
+ }
+
+ status_t getUniqueId(uint64_t* outId) const override {
+ return mBase->getUniqueId(outId);
+ }
+};
+
+IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
+ "android.gui.IGraphicBufferProducer");
// ----------------------------------------------------------------------
diff --git a/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp
new file mode 100644
index 0000000..a5f28cd
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <gui/bufferqueue/1.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+// B2HProducerListener
+B2HProducerListener::B2HProducerListener(
+ sp<BProducerListener> const& base):
+ mBase(base) {
+}
+
+Return<void> B2HProducerListener::onBufferReleased() {
+ mBase->onBufferReleased();
+ return Void();
+}
+
+Return<bool> B2HProducerListener::needsReleaseNotify() {
+ return mBase->needsReleaseNotify();
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
new file mode 100644
index 0000000..eafd296
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -0,0 +1,1234 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "H2BGraphicBufferProducer"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using Status = HGraphicBufferProducer::Status;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+typedef ::android::hardware::media::V1_0::Rect HRect;
+typedef ::android::hardware::media::V1_0::Region HRegion;
+
+// Conversion functions
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline native_handle_t* native_handle_create_from_fd(int fd) {
+ if (fd < 0) {
+ return native_handle_create(0, 0);
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (nh == nullptr) {
+ return nullptr;
+ }
+ nh->data[0] = fd;
+ return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
+ return ((nh == nullptr) || (nh->numFds == 0) ||
+ (nh->numFds <= index) || (index < 0)) ?
+ -1 : nh->data[index];
+}
+
+/**
+ * \brief Convert `Return<Status>` to `status_t`. This is for legacy binder
+ * calls.
+ *
+ * \param[in] t The source `Return<Status>`.
+ * \return The corresponding `status_t`.
+ *
+ * This function first check if \p t has a transport error. If it does, then the
+ * return value is the transport error code. Otherwise, the return value is
+ * converted from `Status` contained inside \p t.
+ *
+ * Note:
+ * - This `Status` is omx-specific. It is defined in `types.hal`.
+ * - The name of this function is not `convert`.
+ */
+// convert: Return<Status> -> status_t
+inline status_t toStatusT(Return<Status> const& t) {
+ return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+inline status_t toStatusT(Return<void> const& t) {
+ return t.isOk() ? OK : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+ t->attr.width = l.getWidth();
+ t->attr.height = l.getHeight();
+ t->attr.stride = l.getStride();
+ t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+ t->attr.layerCount = l.getLayerCount();
+ t->attr.usage = l.getUsage();
+ t->attr.id = l.getId();
+ t->attr.generationNumber = l.getGenerationNumber();
+ t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+ native_handle_t* handle = t.nativeHandle == nullptr ?
+ nullptr : native_handle_clone(t.nativeHandle);
+
+ size_t const numInts = 12 +
+ static_cast<size_t>(handle ? handle->numInts : 0);
+ int32_t* ints = new int32_t[numInts];
+
+ size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+ int* fds = new int[numFds];
+
+ ints[0] = 'GBFR';
+ ints[1] = static_cast<int32_t>(t.attr.width);
+ ints[2] = static_cast<int32_t>(t.attr.height);
+ ints[3] = static_cast<int32_t>(t.attr.stride);
+ ints[4] = static_cast<int32_t>(t.attr.format);
+ ints[5] = static_cast<int32_t>(t.attr.layerCount);
+ ints[6] = static_cast<int32_t>(t.attr.usage);
+ ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+ ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+ ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+ ints[10] = 0;
+ ints[11] = 0;
+ if (handle) {
+ ints[10] = static_cast<int32_t>(handle->numFds);
+ ints[11] = static_cast<int32_t>(handle->numInts);
+ int* intsStart = handle->data + handle->numFds;
+ std::copy(handle->data, intsStart, fds);
+ std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+ }
+
+ void const* constBuffer = static_cast<void const*>(ints);
+ size_t size = numInts * sizeof(int32_t);
+ int const* constFds = static_cast<int const*>(fds);
+ status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+ delete [] fds;
+ delete [] ints;
+ native_handle_delete(handle);
+ return status == NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+inline size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
+ return 4;
+};
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+inline size_t getFenceFdCount(hidl_handle const& fence) {
+ return native_handle_read_fd(fence) == -1 ? 0 : 1;
+}
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numFdsInHandle;
+ FlattenableUtils::read(buffer, size, numFdsInHandle);
+
+ if (numFdsInHandle > 1) {
+ return BAD_VALUE;
+ }
+
+ if (numFds < numFdsInHandle) {
+ return NO_MEMORY;
+ }
+
+ if (numFdsInHandle) {
+ *nh = native_handle_create_from_fd(*fds);
+ if (*nh == nullptr) {
+ return NO_MEMORY;
+ }
+ *fence = *nh;
+ ++fds;
+ --numFds;
+ } else {
+ *nh = nullptr;
+ *fence = hidl_handle();
+ }
+
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] fence The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFenceFlattenedSize(fence) ||
+ numFds < getFenceFdCount(fence)) {
+ return NO_MEMORY;
+ }
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size,
+ static_cast<uint32_t>(getFenceFdCount(fence)));
+ int fd = native_handle_read_fd(fence);
+ if (fd != -1) {
+ *fds = fd;
+ ++fds;
+ --numFds;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+inline bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
+ != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+inline bool convertTo(Fence* l, hidl_handle const& t) {
+ int fd = native_handle_read_fd(t);
+ if (fd != -1) {
+ fd = dup(fd);
+ if (fd == -1) {
+ return false;
+ }
+ }
+ native_handle_t* nh = native_handle_create_from_fd(fd);
+ if (nh == nullptr) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return false;
+ }
+
+ size_t const baseSize = getFenceFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ size_t const baseNumFds = getFenceFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
+ native_handle_delete(nh);
+ return false;
+ }
+ native_handle_delete(nh);
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Unflatten `HRegion`.
+ *
+ * \param[out] t The destination `HRegion`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t unflatten(HRegion* t, void const*& buffer, size_t& size) {
+ if (size < sizeof(uint32_t)) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numRects = 0;
+ FlattenableUtils::read(buffer, size, numRects);
+ if (size < numRects * sizeof(HRect)) {
+ return NO_MEMORY;
+ }
+ if (numRects > (UINT32_MAX / sizeof(HRect))) {
+ return NO_MEMORY;
+ }
+
+ t->resize(numRects);
+ for (size_t r = 0; r < numRects; ++r) {
+ ::android::Rect rect(::android::Rect::EMPTY_RECT);
+ status_t status = rect.unflatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ (*t)[r] = HRect{
+ static_cast<int32_t>(rect.left),
+ static_cast<int32_t>(rect.top),
+ static_cast<int32_t>(rect.right),
+ static_cast<int32_t>(rect.bottom)};
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/IGraphicBufferProducer.cpp:
+// IGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return a lower bound on the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::QueueBufferInput const& /* t */) {
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
+ sizeof(android_dataspace) + // dataSpace
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool); // getFrameTimestamps
+}
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline status_t unflatten(
+ HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->timestamp);
+ int lIsAutoTimestamp;
+ FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
+ t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
+ android_dataspace_t lDataSpace;
+ FlattenableUtils::read(buffer, size, lDataSpace);
+ t->dataSpace = static_cast<Dataspace>(lDataSpace);
+ ::android::Rect lCrop;
+ FlattenableUtils::read(buffer, size, lCrop);
+ t->crop = HRect{
+ static_cast<int32_t>(lCrop.left),
+ static_cast<int32_t>(lCrop.top),
+ static_cast<int32_t>(lCrop.right),
+ static_cast<int32_t>(lCrop.bottom)};
+ int lScalingMode;
+ FlattenableUtils::read(buffer, size, lScalingMode);
+ t->scalingMode = static_cast<int32_t>(lScalingMode);
+ FlattenableUtils::read(buffer, size, t->transform);
+ FlattenableUtils::read(buffer, size, t->stickyTransform);
+ FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
+
+ status_t status = unflattenFence(&(t->fence), nh,
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `IGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `IGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline bool wrapAs(
+ HGraphicBufferProducer::QueueBufferInput* t,
+ native_handle_t** nh,
+ BGraphicBufferProducer::QueueBufferInput const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ constexpr size_t min = sizeof(t.state);
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ return min;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ return min + getFenceFlattenedSize(t.fence);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ return min + sizeof(
+ ::android::FenceTime::Snapshot::signalTime);
+ }
+ return 0;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ return t.state ==
+ HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
+ getFenceFdCount(t.fence) : 0;
+}
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[out] nh The cloned native handle, if necessary.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`, in which case \p nh will be returned.
+ */
+inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ native_handle_t** nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ *nh = nullptr;
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::EMPTY);
+ return NO_ERROR;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::FENCE);
+ *nh = t.fence.getNativeHandle() == nullptr ?
+ nullptr : native_handle_clone(t.fence);
+ return flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
+ FlattenableUtils::write(buffer, size, t.signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return a lower bound on the size of the non-fd buffer required to
+ * flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
+ return sizeof(uint64_t) + // mFrameNumber
+ sizeof(uint8_t) + // mIndex
+ sizeof(uint8_t) + // mAddPostCompositeCalled
+ sizeof(uint8_t) + // mAddRetireCalled
+ sizeof(uint8_t) + // mAddReleaseCalled
+ sizeof(nsecs_t) + // mPostedTime
+ sizeof(nsecs_t) + // mRequestedPresentTime
+ sizeof(nsecs_t) + // mLatchTime
+ sizeof(nsecs_t) + // mFirstRefreshStartTime
+ sizeof(nsecs_t); // mLastRefreshStartTime
+}
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return minFlattenedSize(t) +
+ getFlattenedSize(t.gpuCompositionDoneFence) +
+ getFlattenedSize(t.displayPresentFence) +
+ getFlattenedSize(t.displayRetireFence) +
+ getFlattenedSize(t.releaseFence);
+};
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return getFdCount(t.gpuCompositionDoneFence) +
+ getFdCount(t.displayPresentFence) +
+ getFdCount(t.displayRetireFence) +
+ getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[out] nh The array of native handles that are cloned.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * On success, this function will duplicate file descriptors contained in \p t.
+ * The cloned native handles will be stored in \p nh. These native handles will
+ * need to be closed by the caller.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+// FrameEventsDelta::flatten
+inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ std::vector<native_handle_t*>* nh,
+ void*& buffer, size_t& size, int*& fds, size_t numFds) {
+ // Check that t.index is within a valid range.
+ if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
+ || t.index > std::numeric_limits<uint8_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ FlattenableUtils::write(buffer, size, t.frameNumber);
+
+ // These are static_cast to uint8_t for alignment.
+ FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addRetireCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
+
+ FlattenableUtils::write(buffer, size, t.postedTimeNs);
+ FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
+ FlattenableUtils::write(buffer, size, t.latchTimeNs);
+ FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
+ tSnapshot[0] = &t.gpuCompositionDoneFence;
+ tSnapshot[1] = &t.displayPresentFence;
+ tSnapshot[2] = &t.displayRetireFence;
+ tSnapshot[3] = &t.releaseFence;
+ nh->resize(4);
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = flatten(
+ *(tSnapshot[snapshotIndex]),
+ &((*nh)[snapshotIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (snapshotIndex > 0) {
+ --snapshotIndex;
+ native_handle_close((*nh)[snapshotIndex]);
+ native_handle_delete((*nh)[snapshotIndex]);
+ (*nh)[snapshotIndex] = nullptr;
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t size = 4 + // mDeltas.size()
+ sizeof(t.compositorTiming);
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ size += getFlattenedSize(t.deltas[i]);
+ }
+ return size;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t numFds = 0;
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ numFds += getFdCount(t.deltas[i]);
+ }
+ return numFds;
+}
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[out] nh The array of arrays of cloned native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * On success, this function will duplicate file descriptors contained in \p t.
+ * The cloned native handles will be stored in \p nh. Before making the call, \p
+ * nh should have enough space to store `n` pointers to arrays of native
+ * handles, where `n` is the length of `t.deltas`, and each `nh[i]` should have
+ * enough space to store `4` native handles.
+ */
+inline status_t flatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+ nh->resize(t.deltas.size());
+ for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+ status_t status = flatten(
+ t.deltas[deltaIndex], &((*nh)[deltaIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (deltaIndex > 0) {
+ --deltaIndex;
+ for (size_t snapshotIndex = 0;
+ snapshotIndex < 4; ++snapshotIndex) {
+ native_handle_close((*nh)[deltaIndex][snapshotIndex]);
+ native_handle_delete((*nh)[deltaIndex][snapshotIndex]);
+ (*nh)[deltaIndex][snapshotIndex] = nullptr;
+ }
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+inline bool convertTo(
+ ::android::FrameEventHistoryDelta* l,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ std::vector<std::vector<native_handle_t*> > nhAA;
+ if (flatten(t, &nhAA, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ for (auto nhA : nhAA) {
+ for (auto nh : nhA) {
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
+ }
+ }
+ return false;
+ }
+
+ for (auto nhA : nhAA) {
+ for (auto nh : nhA) {
+ if (nh != nullptr) {
+ native_handle_delete(nh);
+ }
+ }
+ }
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/IGraphicBufferProducer.cpp:
+// IGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `IGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `IGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// IGraphicBufferProducer::QueueBufferOutput
+inline bool convertTo(
+ BGraphicBufferProducer::QueueBufferOutput* l,
+ HGraphicBufferProducer::QueueBufferOutput const& t) {
+ if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
+ return false;
+ }
+ l->width = t.width;
+ l->height = t.height;
+ l->transformHint = t.transformHint;
+ l->numPendingBuffers = t.numPendingBuffers;
+ l->nextFrameNumber = t.nextFrameNumber;
+ l->bufferReplaced = t.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `IGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `IGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+inline HGraphicBufferProducer::DisconnectMode toHDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l) {
+ switch (l) {
+ case BGraphicBufferProducer::DisconnectMode::Api:
+ return HGraphicBufferProducer::DisconnectMode::API;
+ case BGraphicBufferProducer::DisconnectMode::AllLocal:
+ return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
+ }
+ return HGraphicBufferProducer::DisconnectMode::API;
+}
+
+// H2BGraphicBufferProducer
+
+status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+ *buf = new GraphicBuffer();
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->requestBuffer(
+ static_cast<int32_t>(slot),
+ [&fnStatus, &buf] (Status status, AnwBuffer const& buffer) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(buf->get(), buffer)) {
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ return toStatusT(mBase->setMaxDequeuedBufferCount(
+ static_cast<int32_t>(maxDequeuedBuffers)));
+}
+
+status_t H2BGraphicBufferProducer::setAsyncMode(bool async) {
+ return toStatusT(mBase->setAsyncMode(async));
+}
+
+status_t H2BGraphicBufferProducer::dequeueBuffer(
+ int* slot, sp<Fence>* fence,
+ uint32_t w, uint32_t h, ::android::PixelFormat format,
+ uint32_t usage, FrameEventHistoryDelta* outTimestamps) {
+ *fence = new Fence();
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->dequeueBuffer(
+ w, h, static_cast<PixelFormat>(format), usage,
+ outTimestamps != nullptr,
+ [&fnStatus, slot, fence, outTimestamps] (
+ Status status,
+ int32_t tSlot,
+ hidl_handle const& tFence,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
+ fnStatus = toStatusT(status);
+ *slot = tSlot;
+ if (!convertTo(fence->get(), tFence)) {
+ ALOGE("H2BGraphicBufferProducer::dequeueBuffer - "
+ "Invalid output fence");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+ ALOGE("H2BGraphicBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachBuffer(int slot) {
+ return toStatusT(mBase->detachBuffer(static_cast<int>(slot)));
+}
+
+status_t H2BGraphicBufferProducer::detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+ *outBuffer = new GraphicBuffer();
+ *outFence = new Fence();
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->detachNextBuffer(
+ [&fnStatus, outBuffer, outFence] (
+ Status status,
+ AnwBuffer const& tBuffer,
+ hidl_handle const& tFence) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(outFence->get(), tFence)) {
+ ALOGE("H2BGraphicBufferProducer::detachNextBuffer - "
+ "Invalid output fence");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ if (!convertTo(outBuffer->get(), tBuffer)) {
+ ALOGE("H2BGraphicBufferProducer::detachNextBuffer - "
+ "Invalid output buffer");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::attachBuffer(
+ int* outSlot, const sp<GraphicBuffer>& buffer) {
+ AnwBuffer tBuffer;
+ wrapAs(&tBuffer, *buffer);
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->attachBuffer(tBuffer,
+ [&fnStatus, outSlot] (Status status, int32_t slot) {
+ fnStatus = toStatusT(status);
+ *outSlot = slot;
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::queueBuffer(
+ int slot,
+ const QueueBufferInput& input,
+ QueueBufferOutput* output) {
+ HGraphicBufferProducer::QueueBufferInput tInput;
+ native_handle_t* nh;
+ if (!wrapAs(&tInput, &nh, input)) {
+ ALOGE("H2BGraphicBufferProducer::queueBuffer - "
+ "Invalid input");
+ return BAD_VALUE;
+ }
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->queueBuffer(slot, tInput,
+ [&fnStatus, output] (
+ Status status,
+ HGraphicBufferProducer::QueueBufferOutput const& tOutput) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(output, tOutput)) {
+ ALOGE("H2BGraphicBufferProducer::queueBuffer - "
+ "Invalid output");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ native_handle_delete(nh);
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+ hidl_handle tFence;
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+ ALOGE("H2BGraphicBufferProducer::cancelBuffer - "
+ "Invalid input fence");
+ return BAD_VALUE;
+ }
+
+ status_t status = toStatusT(mBase->cancelBuffer(
+ static_cast<int32_t>(slot), tFence));
+ native_handle_delete(nh);
+ return status;
+}
+
+int H2BGraphicBufferProducer::query(int what, int* value) {
+ int result;
+ status_t transStatus = toStatusT(mBase->query(
+ static_cast<int32_t>(what),
+ [&result, value] (int32_t tResult, int32_t tValue) {
+ result = static_cast<int>(tResult);
+ *value = static_cast<int>(tValue);
+ }));
+ return transStatus == NO_ERROR ? result : static_cast<int>(transStatus);
+}
+
+status_t H2BGraphicBufferProducer::connect(
+ const sp<IProducerListener>& listener, int api,
+ bool producerControlledByApp, QueueBufferOutput* output) {
+ sp<HProducerListener> tListener = listener == nullptr ?
+ nullptr : new B2HProducerListener(listener);
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->connect(
+ tListener, static_cast<int32_t>(api), producerControlledByApp,
+ [&fnStatus, output] (
+ Status status,
+ HGraphicBufferProducer::QueueBufferOutput const& tOutput) {
+ fnStatus = toStatusT(status);
+ if (!convertTo(output, tOutput)) {
+ ALOGE("H2BGraphicBufferProducer::connect - "
+ "Invalid output");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) {
+ return toStatusT(mBase->disconnect(
+ static_cast<int32_t>(api), toHDisconnectMode(mode)));
+}
+
+status_t H2BGraphicBufferProducer::setSidebandStream(
+ const sp<NativeHandle>& stream) {
+ return toStatusT(mBase->setSidebandStream(stream->handle()));
+}
+
+void H2BGraphicBufferProducer::allocateBuffers(uint32_t width, uint32_t height,
+ ::android::PixelFormat format, uint32_t usage) {
+ mBase->allocateBuffers(
+ width, height, static_cast<PixelFormat>(format), usage);
+}
+
+status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
+ return toStatusT(mBase->allowAllocation(allow));
+}
+
+status_t H2BGraphicBufferProducer::setGenerationNumber(uint32_t generationNumber) {
+ return toStatusT(mBase->setGenerationNumber(generationNumber));
+}
+
+String8 H2BGraphicBufferProducer::getConsumerName() const {
+ String8 lName;
+ mBase->getConsumerName([&lName] (hidl_string const& name) {
+ lName = name.c_str();
+ });
+ return lName;
+}
+
+status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
+ return toStatusT(mBase->setSharedBufferMode(sharedBufferMode));
+}
+
+status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
+ return toStatusT(mBase->setAutoRefresh(autoRefresh));
+}
+
+status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) {
+ return toStatusT(mBase->setDequeueTimeout(static_cast<int64_t>(timeout)));
+}
+
+status_t H2BGraphicBufferProducer::getLastQueuedBuffer(
+ sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence,
+ float outTransformMatrix[16]) {
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->getLastQueuedBuffer(
+ [&fnStatus, outBuffer, outFence, &outTransformMatrix] (
+ Status status,
+ AnwBuffer const& buffer,
+ hidl_handle const& fence,
+ hidl_array<float, 16> const& transformMatrix) {
+ fnStatus = toStatusT(status);
+ *outBuffer = new GraphicBuffer();
+ if (!convertTo(outBuffer->get(), buffer)) {
+ ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
+ "Invalid output buffer");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ *outFence = new Fence();
+ if (!convertTo(outFence->get(), fence)) {
+ ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence");
+ fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+ }
+ std::copy(transformMatrix.data(),
+ transformMatrix.data() + 16,
+ outTransformMatrix);
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+ mBase->getFrameTimestamps([outDelta] (
+ HGraphicBufferProducer::FrameEventHistoryDelta const& tDelta) {
+ convertTo(outDelta, tDelta);
+ });
+}
+
+status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const {
+ status_t fnStatus;
+ status_t transStatus = toStatusT(mBase->getUniqueId(
+ [&fnStatus, outId] (Status status, uint64_t id) {
+ fnStatus = toStatusT(status);
+ *outId = id;
+ }));
+ return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index 3ca8bd1..ef1e45f 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -21,6 +21,7 @@
#include <limits>
#include <type_traits>
+#ifndef LIKELY
#ifdef __cplusplus
# define LIKELY( exp ) (__builtin_expect( !!(exp), true ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
@@ -28,6 +29,7 @@
# define LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
#endif
+#endif
#if __cplusplus >= 201402L
#define CONSTEXPR constexpr
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 34c136a..a85d16e 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -69,3 +69,20 @@
int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
}
+
+int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform) {
+ static_assert(ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL == NATIVE_WINDOW_TRANSFORM_FLIP_H);
+ static_assert(ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL == NATIVE_WINDOW_TRANSFORM_FLIP_V);
+ static_assert(ANATIVEWINDOW_TRANSFORM_ROTATE_90 == NATIVE_WINDOW_TRANSFORM_ROT_90);
+
+ constexpr int32_t kAllTransformBits =
+ ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
+ ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
+ ANATIVEWINDOW_TRANSFORM_ROTATE_90;
+ if (!window || !getWindowProp(window, NATIVE_WINDOW_IS_VALID))
+ return -EINVAL;
+ if ((transform & ~kAllTransformBits) != 0)
+ return -EINVAL;
+
+ return native_window_set_buffers_transform(window, transform);
+}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 9c5f096..2668927 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -34,6 +34,10 @@
clang: true,
+ cppflags: [
+ "-std=c++1z"
+ ],
+
srcs: [
"AHardwareBuffer.cpp",
"ANativeWindow.cpp",
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6a46d7f..6cd5df3 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -50,6 +50,25 @@
WINDOW_FORMAT_RGB_565 = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
};
+/**
+ * Transforms that can be applied to buffers as they are displayed to a window.
+ *
+ * Supported transforms are any combination of horizontal mirror, vertical
+ * mirror, and clockwise 90 degree rotation, in that order. Rotations of 180
+ * and 270 degrees are made up of those basic transforms.
+ */
+enum ANativeWindowTransform {
+ ANATIVEWINDOW_TRANSFORM_IDENTITY = 0x00,
+ ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL = 0x01,
+ ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL = 0x02,
+ ANATIVEWINDOW_TRANSFORM_ROTATE_90 = 0x04,
+
+ ANATIVEWINDOW_TRANSFORM_ROTATE_180 = ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
+ ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL,
+ ANATIVEWINDOW_TRANSFORM_ROTATE_270 = ANATIVEWINDOW_TRANSFORM_ROTATE_180 |
+ ANATIVEWINDOW_TRANSFORM_ROTATE_90,
+};
+
struct ANativeWindow;
/**
* {@link ANativeWindow} is opaque type that provides access to a native window.
@@ -147,6 +166,19 @@
*/
int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
+#if __ANDROID_API__ >= __ANDROID_API_O__
+
+/**
+ * Set a transform that will be applied to future buffers posted to the window.
+ *
+ * @param transform combination of {@link ANativeWindowTransform} flags
+ * @return 0 if successful
+ * @return -EINVAL if @param transform is invalid
+ */
+int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform);
+
+#endif // __ANDROID_API__ >= __ANDROID_API_O__
+
#ifdef __cplusplus
};
#endif
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index dcfabac..b29c888 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -20,6 +20,7 @@
ANativeWindow_lock;
ANativeWindow_release;
ANativeWindow_setBuffersGeometry;
+ ANativeWindow_setBuffersTransform;
ANativeWindow_unlockAndPost;
local:
*;
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 6a86bb5..49390d9 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -211,8 +211,8 @@
"Display P3",
{{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
- std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f)
+ std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f),
+ std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f)
};
}
diff --git a/libs/vr/libbufferhubqueue/Android.mk b/libs/vr/libbufferhubqueue/Android.mk
index 3ed7ff2..d53f06a 100644
--- a/libs/vr/libbufferhubqueue/Android.mk
+++ b/libs/vr/libbufferhubqueue/Android.mk
@@ -36,10 +36,12 @@
liblog \
libui \
libutils \
+ libgui \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
LOCAL_C_INCLUDES := $(includeFiles)
+LOCAL_CFLAGS := -DLOG_TAG=\"libbufferhubqueue\"
LOCAL_EXPORT_C_INCLUDE_DIRS := $(includeFiles)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 0576b21..bad9503 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -1,5 +1,7 @@
#include "include/private/dvr/buffer_hub_queue_client.h"
+//#define LOG_NDEBUG 0
+
#include <inttypes.h>
#include <log/log.h>
#include <sys/epoll.h>
@@ -24,6 +26,7 @@
meta_size_(meta_size),
meta_buffer_tmp_(meta_size ? new uint8_t[meta_size] : nullptr),
buffers_(BufferHubQueue::kMaxQueueCapacity),
+ epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
available_buffers_(BufferHubQueue::kMaxQueueCapacity),
capacity_(0) {
Initialize();
@@ -36,6 +39,7 @@
meta_size_(meta_size),
meta_buffer_tmp_(meta_size ? new uint8_t[meta_size] : nullptr),
buffers_(BufferHubQueue::kMaxQueueCapacity),
+ epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
available_buffers_(BufferHubQueue::kMaxQueueCapacity),
capacity_(0) {
Initialize();
@@ -101,31 +105,12 @@
ALOGD("New BufferHubQueue event %d: index=%" PRId64, i, index);
- if (is_buffer_event_index(index) && (events[i].events & EPOLLIN)) {
- auto buffer = buffers_[index];
- ret = OnBufferReady(buffer);
- if (ret < 0) {
- ALOGE("Failed to set buffer ready: %s", strerror(-ret));
- continue;
- }
- Enqueue(buffer, index);
- } else if (is_buffer_event_index(index) &&
- (events[i].events & EPOLLHUP)) {
- // This maybe caused by producer replacing an exising buffer slot.
- // Currently the epoll FD is cleaned up when the replacement consumer
- // client is imported.
- ALOGW("Receives EPOLLHUP at slot: %" PRId64, index);
- } else if (is_queue_event_index(index) && (events[i].events & EPOLLIN)) {
- // Note that after buffer imports, if |count()| still returns 0, epoll
- // wait will be tried again to acquire the newly imported buffer.
- ret = OnBufferAllocated();
- if (ret < 0) {
- ALOGE("Failed to import buffer: %s", strerror(-ret));
- continue;
- }
+ if (is_buffer_event_index(index)) {
+ HandleBufferEvent(static_cast<size_t>(index), events[i]);
+ } else if (is_queue_event_index(index)) {
+ HandleQueueEvent(events[i]);
} else {
- ALOGW("Unknown event %d: u64=%" PRId64 ": events=%" PRIu32, i, index,
- events[i].events);
+ ALOGW("Unknown event index: %" PRId64, index);
}
}
}
@@ -133,6 +118,68 @@
return true;
}
+void BufferHubQueue::HandleBufferEvent(size_t slot, const epoll_event& event) {
+ auto buffer = buffers_[slot];
+ if (!buffer) {
+ ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
+ return;
+ }
+
+ auto status = buffer->GetEventMask(event.events);
+ if (!status) {
+ ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
+ status.GetErrorMessage().c_str());
+ return;
+ }
+
+ int events = status.get();
+ if (events & EPOLLIN) {
+ int ret = OnBufferReady(buffer);
+ if (ret < 0) {
+ ALOGE("Failed to set buffer ready: %s", strerror(-ret));
+ return;
+ }
+ Enqueue(buffer, slot);
+ } else if (events & EPOLLHUP) {
+ // This might be caused by producer replacing an existing buffer slot, or
+ // when BufferHubQueue is shutting down. For the first case, currently the
+ // epoll FD is cleaned up when the replacement consumer client is imported,
+ // we shouldn't detach again if |epollhub_pending_[slot]| is set.
+ ALOGW(
+ "Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP "
+ "pending: %d",
+ slot, buffer->event_fd(), epollhup_pending_[slot]);
+ if (epollhup_pending_[slot]) {
+ epollhup_pending_[slot] = false;
+ } else {
+ DetachBuffer(slot);
+ }
+ } else {
+ ALOGW("Unknown event, slot=%zu, epoll events=%d", slot, events);
+ }
+}
+
+void BufferHubQueue::HandleQueueEvent(const epoll_event& event) {
+ auto status = GetEventMask(event.events);
+ if (!status) {
+ ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
+ status.GetErrorMessage().c_str());
+ return;
+ }
+
+ int events = status.get();
+ if (events & EPOLLIN) {
+ // Note that after buffer imports, if |count()| still returns 0, epoll
+ // wait will be tried again to acquire the newly imported buffer.
+ int ret = OnBufferAllocated();
+ if (ret < 0) {
+ ALOGE("Failed to import buffer: %s", strerror(-ret));
+ }
+ } else {
+ ALOGW("Unknown epoll events=%d", events);
+ }
+}
+
int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf,
size_t slot) {
if (is_full()) {
@@ -146,8 +193,9 @@
if (buffers_[slot] != nullptr) {
// Replace the buffer if the slot is preoccupied. This could happen when the
// producer side replaced the slot with a newly allocated buffer. Detach the
- // buffer and set up with the new one.
+ // buffer before setting up with the new one.
DetachBuffer(slot);
+ epollhup_pending_[slot] = true;
}
epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u64 = slot}};
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
index 1ea3994..02bca09 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
@@ -1,5 +1,7 @@
#include "include/private/dvr/buffer_hub_queue_consumer.h"
+//#define LOG_NDEBUG 0
+
namespace android {
namespace dvr {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
index a108042..b013c85 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
@@ -1,5 +1,8 @@
#include "include/private/dvr/buffer_hub_queue_core.h"
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BufferHubQueueCore"
+
#include <log/log.h>
namespace android {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 752e8c4..7ddf49b 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -1,5 +1,7 @@
#include "include/private/dvr/buffer_hub_queue_producer.h"
+//#define LOG_NDEBUG 0
+
#include <inttypes.h>
#include <log/log.h>
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 83e77d4..1f2830a 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -49,6 +49,14 @@
return buffers_[slot];
}
+ Status<int> GetEventMask(int events) {
+ if (auto* client_channel = GetChannel()) {
+ return client_channel->GetEventMask(events);
+ } else {
+ return pdx::ErrorStatus(EINVAL);
+ }
+ }
+
// Enqueue a buffer marks buffer to be available (|Gain|'ed for producer
// and |Acquire|'ed for consumer. This is only used for internal bookkeeping.
void Enqueue(std::shared_ptr<BufferHubBuffer> buf, size_t slot);
@@ -87,6 +95,9 @@
// Wait for buffers to be released and re-add them to the queue.
bool WaitForBuffers(int timeout);
+ void HandleBufferEvent(size_t slot, const epoll_event& event);
+ void HandleQueueEvent(const epoll_event& event);
+
virtual int OnBufferReady(std::shared_ptr<BufferHubBuffer> buf) = 0;
// Called when a buffer is allocated remotely.
@@ -160,6 +171,30 @@
// |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|.
std::vector<std::shared_ptr<BufferHubBuffer>> buffers_;
+ // |epollhup_pending_| tracks whether a slot of |buffers_| get detached before
+ // its corresponding EPOLLHUP event got handled. This could happen as the
+ // following sequence:
+ // 1. Producer queue's client side allocates a new buffer (at slot 1).
+ // 2. Producer queue's client side replaces an existing buffer (at slot 0).
+ // This is implemented by first detaching the buffer and then allocating a
+ // new buffer.
+ // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
+ // event on the queue which indicates a new buffer is avaiable and the
+ // EPOLLHUP event for slot 0. Consumer handles these two events in order.
+ // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
+ // slot 0 and (the new) slot 1 buffer will be imported. During the import
+ // of the buffer at slot 1, consuemr client detaches the old buffer so that
+ // the new buffer can be registered. At the same time
+ // |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
+ // was detached prior to EPOLLHUP event.
+ // 5. Consumer client continues to handle the EPOLLHUP. Since
+ // |epollhup_pending_[slot]| is marked as true, it can safely ignore the
+ // event without detaching the newly allocated buffer at slot 1.
+ //
+ // In normal situations where the previously described sequence doesn't
+ // happen, an EPOLLHUP event should trigger a regular buffer detach.
+ std::vector<bool> epollhup_pending_;
+
// |available_buffers_| uses |dvr::RingBuffer| to implementation queue
// sematics. When |Dequeue|, we pop the front element from
// |available_buffers_|, and that buffer's reference count will decrease by
@@ -225,7 +260,7 @@
// Returns Zero on success and negative error code when buffer allocation
// fails.
int AllocateBuffer(int width, int height, int format, int usage,
- size_t buffer_count, size_t* out_slot);
+ size_t slice_count, size_t* out_slot);
// Add a producer buffer to populate the queue. Once added, a producer buffer
// is available to use (i.e. in |Gain|'ed mode).
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 8fd3627..fe18619 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -98,14 +98,9 @@
int dvrDisplayManagerClientGetSurfaceBuffers(
DvrDisplayManagerClient* client, int surface_id,
DvrDisplayManagerClientSurfaceBuffers** surface_buffers) {
- std::vector<std::unique_ptr<android::dvr::BufferConsumer>> buffer_list;
- int ret = client->client->GetSurfaceBuffers(surface_id, &buffer_list);
- if (ret < 0)
- return ret;
-
- *surface_buffers =
- new DvrDisplayManagerClientSurfaceBuffers(std::move(buffer_list));
- return ret;
+ // TODO(jwcai, hendrikw) Remove this after we replacing
+ // dvrDisplayManagerClientGetSurfaceBuffers is dvr_api.
+ return -1;
}
void dvrDisplayManagerClientSurfaceBuffersDestroy(
diff --git a/libs/vr/libdisplay/display_manager_client_impl.cpp b/libs/vr/libdisplay/display_manager_client_impl.cpp
index 82198b9..3fbd1e0 100644
--- a/libs/vr/libdisplay/display_manager_client_impl.cpp
+++ b/libs/vr/libdisplay/display_manager_client_impl.cpp
@@ -31,27 +31,5 @@
return 0;
}
-int DisplayManagerClient::GetSurfaceBuffers(
- int surface_id, std::vector<std::unique_ptr<BufferConsumer>>* consumers) {
- auto status =
- InvokeRemoteMethod<DisplayManagerRPC::GetSurfaceBuffers>(surface_id);
- if (!status) {
- ALOGE(
- "DisplayManagerClient::GetSurfaceBuffers: Failed to get buffers for "
- "surface_id=%d: %s",
- surface_id, status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- std::vector<std::unique_ptr<BufferConsumer>> consumer_buffers;
- std::vector<LocalChannelHandle> channel_handles = status.take();
- for (auto&& handle : channel_handles) {
- consumer_buffers.push_back(BufferConsumer::Import(std::move(handle)));
- }
-
- *consumers = std::move(consumer_buffers);
- return 0;
-}
-
} // namespace dvr
} // namespace android
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 8ba9175..f515b8f 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -62,10 +62,8 @@
bool dvrDisplayManagerClientSurfaceListGetClientIsVisible(
DvrDisplayManagerClientSurfaceList* surface_list, size_t index);
-// Populates |surface_buffers| with the list of buffers for |surface_id|.
-// |surface_id| should be a valid ID from the list of surfaces.
-//
-// @return Returns 0 on success. Otherwise it returns a negative error value.
+// TODO(jwcai, hendrikw) Remove this after we replacing
+// dvrDisplayManagerClientGetSurfaceBuffers is dvr_api.
int dvrDisplayManagerClientGetSurfaceBuffers(
DvrDisplayManagerClient* client, int surface_id,
DvrDisplayManagerClientSurfaceBuffers** surface_buffers);
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 4ecd8d4..0897126 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
@@ -17,9 +17,6 @@
int GetSurfaceList(std::vector<DisplaySurfaceInfo>* surface_list);
- int GetSurfaceBuffers(
- int surface_id, std::vector<std::unique_ptr<BufferConsumer>>* consumers);
-
using Client::event_fd;
using Client::GetChannel;
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index 1c1a5e0..d37aed7 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -258,7 +258,6 @@
// Op codes.
enum {
kOpGetSurfaceList = 0,
- kOpGetSurfaceBuffers,
kOpUpdateSurfaces,
};
@@ -269,8 +268,6 @@
// Methods.
PDX_REMOTE_METHOD(GetSurfaceList, kOpGetSurfaceList,
std::vector<DisplaySurfaceInfo>(Void));
- PDX_REMOTE_METHOD(GetSurfaceBuffers, kOpGetSurfaceBuffers,
- std::vector<LocalChannelHandle>(int surface_id));
PDX_REMOTE_METHOD(
UpdateSurfaces, kOpUpdateSurfaces,
int(const std::map<int, DisplaySurfaceAttributes>& updates));
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client_api.h b/libs/vr/libdisplay/include/private/dvr/vsync_client_api.h
index b8135e3..0ae5cd5 100644
--- a/libs/vr/libdisplay/include/private/dvr/vsync_client_api.h
+++ b/libs/vr/libdisplay/include/private/dvr/vsync_client_api.h
@@ -12,7 +12,7 @@
// The "dvr_vsync_client" structure wraps a client connection to the
// system vsync service. It is used to synchronize application drawing
// with the scanout of the display.
-typedef struct dvr_vsync_client dreamos_vsync_client;
+typedef struct dvr_vsync_client dvr_vsync_client;
// Creates a new client to the system vsync service.
dvr_vsync_client* dvr_vsync_client_create();
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 6730ba8..6df1642 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -77,11 +77,6 @@
*this, &DisplayManagerService::OnGetSurfaceList, message);
return 0;
- case DisplayManagerRPC::GetSurfaceBuffers::Opcode:
- DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceBuffers>(
- *this, &DisplayManagerService::OnGetSurfaceBuffers, message);
- return 0;
-
case DisplayManagerRPC::UpdateSurfaces::Opcode:
DispatchRemoteMethod<DisplayManagerRPC::UpdateSurfaces>(
*this, &DisplayManagerService::OnUpdateSurfaces, message);
@@ -128,26 +123,6 @@
return items;
}
-std::vector<LocalChannelHandle> DisplayManagerService::OnGetSurfaceBuffers(
- pdx::Message& message, int surface_id) {
- std::shared_ptr<DisplaySurface> surface =
- display_service_->GetDisplaySurface(surface_id);
- if (!surface)
- REPLY_ERROR_RETURN(message, ENOENT, {});
-
- std::vector<LocalChannelHandle> consumers;
- int ret = surface->GetConsumers(&consumers);
- if (ret < 0) {
- ALOGE(
- "DisplayManagerService::OnGetDisplaySurfaceBuffers: Failed to get "
- "consumers for surface %d: %s",
- surface_id, strerror(-ret));
- REPLY_ERROR_RETURN(message, -ret, {});
- }
-
- return consumers;
-}
-
int DisplayManagerService::OnUpdateSurfaces(
pdx::Message& /*message*/,
const std::map<int, DisplaySurfaceAttributes>& updates) {
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 46401fa..3f83c7d 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -51,8 +51,6 @@
const std::shared_ptr<DisplayService>& display_service);
std::vector<DisplaySurfaceInfo> OnGetSurfaceList(pdx::Message& message);
- std::vector<pdx::LocalChannelHandle> OnGetSurfaceBuffers(
- pdx::Message& message, int surface_id);
int OnUpdateSurfaces(pdx::Message& message,
const std::map<int, DisplaySurfaceAttributes>& updates);
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 7c821bf..d427ea6 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -84,22 +84,6 @@
client_blur_behind_ = blur_behind;
}
-size_t DisplaySurface::GetBufferCount() const {
- std::lock_guard<std::mutex> autolock(lock_);
- return buffers_.size();
-}
-
-std::vector<std::shared_ptr<BufferConsumer>> DisplaySurface::GetBuffers() {
- std::lock_guard<std::mutex> autolock(lock_);
- std::vector<std::shared_ptr<BufferConsumer>> return_vector(buffers_.size());
-
- for (const auto pair : buffers_) {
- return_vector.push_back(pair.second);
- }
-
- return return_vector;
-}
-
AcquiredBuffer DisplaySurface::AcquireNewestAvailableBuffer(
AcquiredBuffer* skipped_buffer) {
std::lock_guard<std::mutex> autolock(lock_);
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index b7bcd97..fa34057 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -65,9 +65,6 @@
return buffer_id_to_index_[buffer_id];
}
- size_t GetBufferCount() const;
- std::vector<std::shared_ptr<BufferConsumer>> GetBuffers();
-
// Gets a new set of consumers for all of the surface's buffers. These
// consumers are independent from the consumers maintained internally to the
// surface and may be passed to other processes over IPC.
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 740ead3..4c4cd4e 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -670,12 +670,42 @@
#endif
#endif
-#ifndef EGL_KHR_pixel_format_float
-#define EGL_KHR_pixel_format_float 1
-#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339 // eglChooseConfig and eglGetConfigAttrib attribute
-#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A // Attribute value for COLOR_COMPONENT_TYPE
-#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B // Attribute value for COLOR_COMPONENT_TYPE
-#endif
+#ifndef EGL_EXT_gl_colorspace_bt2020_linear
+#define EGL_EXT_gl_colorspace_bt2020_linear 1
+#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F
+#endif /* EGL_EXT_gl_colorspace_bt2020_linear */
+
+#ifndef EGL_EXT_gl_colorspace_bt2020_pq
+#define EGL_EXT_gl_colorspace_bt2020_pq 1
+#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340
+#endif /* EGL_EXT_gl_colorspace_bt2020_pq */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb_linear
+#define EGL_EXT_gl_colorspace_scrgb_linear 1
+#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
+#endif /* EGL_EXT_gl_colorspace_scrgb_linear */
+
+#ifndef EGL_EXT_pixel_format_float
+#define EGL_EXT_pixel_format_float 1
+#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
+#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
+#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B
+#endif /* EGL_EXT_pixel_format_float */
+
+#ifndef EGL_EXT_surface_SMPTE2086_metadata
+#define EGL_EXT_surface_SMPTE2086_metadata 1
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346
+#define EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347
+#define EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348
+#define EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349
+#define EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A
+#define EGL_METADATA_SCALING_EXT 50000
+#endif /* EGL_EXT_surface_SMPTE2086_metadata */
#ifdef __cplusplus
}
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
index 0f1c925..ea94bc1 100644
--- a/opengl/tests/lib/Android.mk
+++ b/opengl/tests/lib/Android.mk
@@ -24,6 +24,7 @@
LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
+LOCAL_SHARED_LIBRARIES += libgui
LOCAL_STATIC_LIBRARIES := libarect
include $(BUILD_STATIC_LIBRARY)
diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml
index 518c369..af13395 100755
--- a/opengl/tools/glgen2/registry/egl.xml
+++ b/opengl/tools/glgen2/registry/egl.xml
@@ -723,6 +723,23 @@
<enum value="0x3339" name="EGL_COLOR_COMPONENT_TYPE_EXT"/>
<enum value="0x333A" name="EGL_COLOR_COMPONENT_TYPE_FIXED_EXT"/>
<enum value="0x333B" name="EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT"/>
+ <unused start="0x333C" end="0x333E"/>
+ <enum value="0x333F" name="EGL_GL_COLORSPACE_BT2020_LINEAR_EXT"/>
+ <enum value="0x3340" name="EGL_GL_COLORSPACE_BT2020_PQ_EXT"/>
+ <enum value="0x3341" name="EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT"/>
+ <enum value="0x3342" name="EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT"/>
+ <enum value="0x3343" name="EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT"/>
+ <enum value="0x3344" name="EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT"/>
+ <enum value="0x3345" name="EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT"/>
+ <enum value="0x3346" name="EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT"/>
+ <enum value="0x3347" name="EGL_SMPTE2086_WHITE_POINT_X_EXT"/>
+ <enum value="0x3348" name="EGL_SMPTE2086_WHITE_POINT_Y_EXT"/>
+ <enum value="0x3349" name="EGL_SMPTE2086_MAX_LUMINANCE_EXT"/>
+ <enum value="0x334A" name="EGL_SMPTE2086_MIN_LUMINANCE_EXT"/>
+ <enum value="50000" name="EGL_METADATA_SCALING_EXT"/>
+ <unused start="0x334B" end="0x334F"/>
+ <enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
+ <unused start="0x3351" end="0x339F"/>
</enums>
<enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)">
@@ -765,8 +782,8 @@
<!-- Reservable for future use. To generate a new range, allocate multiples
of 16 starting at the lowest available point in this block. -->
- <enums namespace="EGL" start="0x3420" end="0x3FFF" vendor="KHR">
- <unused start="0x3420" end="0x3FFF" comment="Reserved for future use"/>
+ <enums namespace="EGL" start="0x3470" end="0x3FFF" vendor="KHR">
+ <unused start="0x3470" end="0x3FFF" comment="Reserved for future use"/>
</enums>
<enums namespace="EGL" start="0x8F70" end="0x8F7F" vendor="HI" comment="For Mark Callow, Khronos bug 4055. Shared with GL.">
@@ -1859,6 +1876,21 @@
<command name="eglQueryDisplayAttribEXT"/>
</require>
</extension>
+ <extension name="EGL_EXT_gl_colorspace_bt2020_linear" supported="egl">
+ <require>
+ <enum name="EGL_GL_COLORSPACE_BT2020_LINEAR_EXT"/>
+ </require>
+ </extension>
+ <extension name="EGL_EXT_gl_colorspace_bt2020_pq" supported="egl">
+ <require>
+ <enum name="EGL_GL_COLORSPACE_BT2020_PQ_EXT"/>
+ </require>
+ </extension>
+ <extension name="EGL_EXT_gl_colorspace_scrgb_linear" supported="egl">
+ <require>
+ <enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
+ </require>
+ </extension>
<extension name="EGL_EXT_image_dma_buf_import" supported="egl">
<require>
<enum name="EGL_LINUX_DMA_BUF_EXT"/>
@@ -1955,6 +1987,22 @@
<command name="eglStreamConsumerOutputEXT"/>
</require>
</extension>
+ <extension name="EGL_EXT_surface_SMPTE2086_metadata" supported="egl">
+ <require>
+ <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT"/>
+ <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT"/>
+ <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT"/>
+ <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT"/>
+ <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT"/>
+ <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT"/>
+ <enum name="EGL_SMPTE2086_WHITE_POINT_X_EXT"/>
+ <enum name="EGL_SMPTE2086_WHITE_POINT_Y_EXT"/>
+ <enum name="EGL_SMPTE2086_MAX_LUMINANCE_EXT"/>
+ <enum name="EGL_SMPTE2086_MIN_LUMINANCE_EXT"/>
+ <enum name="EGL_METADATA_SCALING_EXT"/>
+ </require>
+ </extension>
+
<extension name="EGL_EXT_swap_buffers_with_damage" supported="egl">
<require>
<command name="eglSwapBuffersWithDamageEXT"/>
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 7bd495f..2a17a7f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -51,7 +51,7 @@
}
}
-SensorDevice::SensorDevice() {
+SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
// SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
size_t retry = 10;
@@ -118,7 +118,15 @@
if (mSensors == NULL) return "HAL not initialized\n";
String8 result;
- checkReturn(mSensors->getSensorsList([&](const auto &list) {
+
+ result.appendFormat("Saw %d hidlTransport Errors\n", mTotalHidlTransportErrors);
+ for (auto it = mHidlTransportErrors.begin() ; it != mHidlTransportErrors.end(); it++ ) {
+ result += "\t";
+ result += it->toString();
+ result += "\n";
+ }
+
+ checkReturn(mSensors->getSensorsList([&](const auto &list){
const size_t count = list.size();
result.appendFormat(
@@ -182,19 +190,44 @@
if (mSensors == NULL) return NO_INIT;
ssize_t err;
+ int numHidlTransportErrors = 0;
+ bool hidlTransportError = false;
- checkReturn(mSensors->poll(
- count,
- [&](auto result,
- const auto &events,
- const auto &dynamicSensorsAdded) {
- if (result == Result::OK) {
- convertToSensorEvents(events, dynamicSensorsAdded, buffer);
- err = (ssize_t)events.size();
- } else {
- err = StatusFromResult(result);
- }
- }));
+ do {
+ auto ret = mSensors->poll(
+ count,
+ [&](auto result,
+ const auto &events,
+ const auto &dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEvents(events, dynamicSensorsAdded, buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = StatusFromResult(result);
+ }
+ });
+
+ if (ret.isOk()) {
+ hidlTransportError = false;
+ } else {
+ hidlTransportError = true;
+ numHidlTransportErrors++;
+ if (numHidlTransportErrors > 50) {
+ // Log error and bail
+ ALOGE("Max Hidl transport errors this cycle : %d", numHidlTransportErrors);
+ handleHidlDeath(ret.description());
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } while (hidlTransportError);
+
+ if(numHidlTransportErrors > 0) {
+ ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
+ HidlTransportErrorLog errLog(time(NULL), numHidlTransportErrors);
+ mHidlTransportErrors.add(errLog);
+ mTotalHidlTransportErrors++;
+ }
return err;
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 03552f6..410531b 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -31,6 +31,8 @@
#include "android/hardware/sensors/1.0/ISensors.h"
+#include "RingBuffer.h"
+
// ---------------------------------------------------------------------------
namespace android {
@@ -41,6 +43,33 @@
class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
public:
+
+ class HidlTransportErrorLog {
+ public:
+
+ HidlTransportErrorLog() {
+ mTs = 0;
+ mCount = 0;
+ }
+
+ HidlTransportErrorLog(time_t ts, int count) {
+ mTs = ts;
+ mCount = count;
+ }
+
+ String8 toString() const {
+ String8 result;
+ struct tm *timeInfo = localtime(&mTs);
+ result.appendFormat("%02d:%02d:%02d :: %d", timeInfo->tm_hour, timeInfo->tm_min,
+ timeInfo->tm_sec, mCount);
+ return result;
+ }
+
+ private:
+ time_t mTs; // timestamp of the error
+ int mCount; // number of transport errors observed
+ };
+
ssize_t getSensorList(sensor_t const** list);
void handleDynamicSensorConnection(int handle, bool connected);
@@ -125,6 +154,10 @@
};
DefaultKeyedVector<int, Info> mActivationCount;
+ // Keep track of any hidl transport failures
+ SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
+ int mTotalHidlTransportErrors;
+
// Use this vector to determine which client is activated or deactivated.
SortedVector<void *> mDisabledClients;
SensorDevice();
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 54d815b..75e8989 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -17,29 +17,76 @@
#ifndef ANDROID_SENSOR_REGISTRATION_INFO_H
#define ANDROID_SENSOR_REGISTRATION_INFO_H
+#include "SensorServiceUtils.h"
+#include <utils/Thread.h>
+#include <iomanip>
+#include <sstream>
+
namespace android {
class SensorService;
-struct SensorService::SensorRegistrationInfo {
- int32_t mSensorHandle;
- String8 mPackageName;
- bool mActivated;
- int32_t mSamplingRateUs;
- int32_t mMaxReportLatencyUs;
- int32_t mHour, mMin, mSec;
-
+class SensorService::SensorRegistrationInfo : public SensorServiceUtil::Dumpable {
+public:
SensorRegistrationInfo() : mPackageName() {
mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
- mHour = mMin = mSec = INT32_MIN;
+ mHour = mMin = mSec = INT8_MIN;
mActivated = false;
}
- static bool isSentinel(const SensorRegistrationInfo& info) {
- return (info.mHour == INT32_MIN &&
- info.mMin == INT32_MIN &&
- info.mSec == INT32_MIN);
+ SensorRegistrationInfo(int32_t handle, const String8 &packageName,
+ int32_t samplingRateNs, int32_t maxReportLatencyNs, bool activate) {
+ mSensorHandle = handle;
+ mPackageName = packageName;
+
+ mSamplingRateUs = static_cast<int32_t>(samplingRateNs/1000);
+ mMaxReportLatencyUs = static_cast<int32_t>(maxReportLatencyNs/1000);
+ mActivated = activate;
+
+ IPCThreadState *thread = IPCThreadState::self();
+ mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
+ mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
+
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ mHour = static_cast<int8_t>(timeinfo->tm_hour);
+ mMin = static_cast<int8_t>(timeinfo->tm_min);
+ mSec = static_cast<int8_t>(timeinfo->tm_sec);
}
+
+ static bool isSentinel(const SensorRegistrationInfo& info) {
+ return (info.mHour == INT8_MIN &&
+ info.mMin == INT8_MIN &&
+ info.mSec == INT8_MIN);
+ }
+
+ // Dumpable interface
+ virtual std::string dump() const override {
+ std::ostringstream ss;
+ ss << std::setfill('0') << std::setw(2) << static_cast<int>(mHour) << ":"
+ << std::setw(2) << static_cast<int>(mMin) << ":"
+ << std::setw(2) << static_cast<int>(mSec)
+ << (mActivated ? " +" : " -")
+ << " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec
+ << std::setfill(' ') << " pid=" << std::setw(5) << mPid
+ << " uid=" << std::setw(5) << mUid << " package=" << mPackageName;
+ if (mActivated) {
+ ss << " samplingPeriod=" << mSamplingRateUs << "us"
+ << " batchingPeriod=" << mMaxReportLatencyUs << "us";
+ };
+ return ss.str();
+ }
+
+private:
+ int32_t mSensorHandle;
+ String8 mPackageName;
+ pid_t mPid;
+ uid_t mUid;
+ int32_t mSamplingRateUs;
+ int32_t mMaxReportLatencyUs;
+ bool mActivated;
+ int8_t mHour, mMin, mSec;
+
};
} // namespace android;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c11df13..8fc4921 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -480,17 +480,7 @@
SENSOR_REGISTRATIONS_BUF_SIZE;
continue;
}
- if (reg_info.mActivated) {
- result.appendFormat("%02d:%02d:%02d activated handle=0x%08x "
- "samplingRate=%dus maxReportLatency=%dus package=%s\n",
- reg_info.mHour, reg_info.mMin, reg_info.mSec, reg_info.mSensorHandle,
- reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs,
- reg_info.mPackageName.string());
- } else {
- result.appendFormat("%02d:%02d:%02d de-activated handle=0x%08x package=%s\n",
- reg_info.mHour, reg_info.mMin, reg_info.mSec,
- reg_info.mSensorHandle, reg_info.mPackageName.string());
- }
+ result.appendFormat("%s\n", reg_info.dump().c_str());
currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
SENSOR_REGISTRATIONS_BUF_SIZE;
} while(startIndex != currentIndex);
@@ -1220,18 +1210,10 @@
if (err == NO_ERROR) {
connection->updateLooperRegistration(mLooper);
- SensorRegistrationInfo ®_info =
- mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
- reg_info.mSensorHandle = handle;
- reg_info.mSamplingRateUs = samplingPeriodNs/1000;
- reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000;
- reg_info.mActivated = true;
- reg_info.mPackageName = connection->getPackageName();
- time_t rawtime = time(NULL);
- struct tm * timeinfo = localtime(&rawtime);
- reg_info.mHour = timeinfo->tm_hour;
- reg_info.mMin = timeinfo->tm_min;
- reg_info.mSec = timeinfo->tm_sec;
+
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
+ SensorRegistrationInfo(handle, connection->getPackageName(),
+ samplingPeriodNs, maxBatchReportLatencyNs, true);
mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
@@ -1254,16 +1236,8 @@
}
if (err == NO_ERROR) {
- SensorRegistrationInfo ®_info =
- mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
- reg_info.mActivated = false;
- reg_info.mPackageName= connection->getPackageName();
- reg_info.mSensorHandle = handle;
- time_t rawtime = time(NULL);
- struct tm * timeinfo = localtime(&rawtime);
- reg_info.mHour = timeinfo->tm_hour;
- reg_info.mMin = timeinfo->tm_min;
- reg_info.mSec = timeinfo->tm_sec;
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
+ SensorRegistrationInfo(handle, connection->getPackageName(), 0, 0, false);
mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
return err;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5583dad..d0be121 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -91,7 +91,7 @@
// nested class/struct for internal use
class SensorRecord;
class SensorEventAckReceiver;
- struct SensorRegistrationInfo;
+ class SensorRegistrationInfo;
enum Mode {
// The regular operating mode where any application can register/unregister/call flush on
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 1c1db74..d325e4d 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -65,13 +65,6 @@
DisplayHardware/HWComposer_hwc1.cpp
endif
-ifeq ($(TARGET_BOARD_PLATFORM),omap4)
- LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
-endif
-ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
- LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
-endif
-
ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true)
LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS
endif
@@ -84,12 +77,6 @@
LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
endif
-ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
- LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
-else
- LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0
-endif
-
ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),)
LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION)
else
@@ -173,6 +160,7 @@
libbinder \
libutils \
libui \
+ libgui \
libdl
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
@@ -211,3 +199,5 @@
include $(BUILD_SHARED_LIBRARY)
endif # libnativehelper
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 86cf17d..d7654f1 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -33,6 +33,7 @@
#include <ui/Fence.h>
#include "DispSync.h"
+#include "SurfaceFlinger.h"
#include "EventLog/EventLog.h"
using std::max;
@@ -54,10 +55,6 @@
// present time and the nearest software-predicted vsync.
static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
-// This is the offset from the present fence timestamps to the corresponding
-// vsync event.
-static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
-
#undef LOG_TAG
#define LOG_TAG "DispSyncThread"
class DispSyncThread: public Thread {
@@ -381,6 +378,7 @@
mRefreshSkipCount(0),
mThread(new DispSyncThread(name)) {
+ mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
// set DispSync to SCHED_FIFO to minimize jitter
struct sched_param param = {0};
@@ -433,7 +431,7 @@
nsecs_t t = f->getSignalTime();
if (t < INT64_MAX) {
mPresentFences[i].clear();
- mPresentTimes[i] = t + kPresentTimeOffset;
+ mPresentTimes[i] = t + mPresentTimeOffset;
}
}
}
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 2763e59..5b7083d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -182,6 +182,10 @@
// mMutex is used to protect access to all member variables.
mutable Mutex mMutex;
+
+ // This is the offset from the present fence timestamps to the corresponding
+ // vsync event.
+ int64_t mPresentTimeOffset;
};
}
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 9909bf9..e3dbecc 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -23,6 +23,9 @@
#include "GLExtensions.h"
#include "Mesh.h"
+#include <vector>
+#include <SurfaceFlinger.h>
+
EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
// ---------------------------------------------------------------------------
@@ -76,18 +79,21 @@
LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
}
- // Also create our EGLContext
- EGLint contextAttributes[] = {
- EGL_CONTEXT_CLIENT_VERSION, contextClientVersion, // MUST be first
+ std::vector<EGLint> contextAttributes;
+ contextAttributes.reserve(6);
+ contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ contextAttributes.push_back(contextClientVersion);
#ifdef EGL_IMG_context_priority
-#ifdef HAS_CONTEXT_PRIORITY
-#warning "using EGL_IMG_context_priority"
- EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
+ if (SurfaceFlinger::useContextPriority) {
+ contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+ contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ }
#endif
-#endif
- EGL_NONE, EGL_NONE
- };
- EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes);
+ contextAttributes.push_back(EGL_NONE);
+ contextAttributes.push_back(EGL_NONE);
+
+ EGLContext ctxt = eglCreateContext(display, config, NULL,
+ contextAttributes.data());
// if can't create a GL context, we can only abort.
LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8420807..2eb880a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -112,6 +112,8 @@
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
+bool SurfaceFlinger::useContextPriority;
+int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
@@ -164,6 +166,12 @@
ALOGI("SurfaceFlinger is starting");
+ useContextPriority = getBool< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::useContextPriority>(false);
+
+ dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
+
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -3224,14 +3232,12 @@
void SurfaceFlinger::appendSfConfigString(String8& result) const
{
result.append(" [sf");
-#ifdef HAS_CONTEXT_PRIORITY
- result.append(" HAS_CONTEXT_PRIORITY");
-#endif
-#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
- result.append(" NEVER_DEFAULT_TO_ASYNC_MODE");
-#endif
+ result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
+
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
+
+ result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64 , dispSyncPresentTimeOffset);
result.append("]");
}
@@ -3358,9 +3364,9 @@
result.append("DispSync configuration: ");
colorizer.reset(result);
result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
- "present offset %d ns (refresh %" PRId64 " ns)",
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
- PRESENT_TIME_OFFSET_FROM_VSYNC_NS, activeConfig->getVsyncPeriod());
+ dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
result.append("\n");
// Dump static screen stats
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7269afe..0b4be4a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -129,6 +129,13 @@
static int64_t vsyncPhaseOffsetNs;
static int64_t sfVsyncPhaseOffsetNs;
+ // Instruct the Render Engine to use EGL_IMG_context_priority is available.
+ static bool useContextPriority;
+
+ // The offset in nanoseconds to use when DispSync timestamps present fence
+ // signaling time.
+ static int64_t dispSyncPresentTimeOffset;
+
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
}
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 01226e0..1d2b485 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -179,7 +179,7 @@
const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
// The DispSync time is already adjusted for the difference between
- // vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so
+ // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
// we don't need to factor that in here. Pad a little to avoid
// weird effects if apps might be requesting times right on the edge.
nsecs_t extraPadding = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 8c651da..eee0a46 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -111,6 +111,8 @@
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
+bool SurfaceFlinger::useContextPriority;
+int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
@@ -155,6 +157,12 @@
ALOGI("SurfaceFlinger is starting");
+ useContextPriority = getBool< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::useContextPriority>(false);
+
+ dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
+
char value[PROPERTY_VALUE_MAX];
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -2996,14 +3004,11 @@
void SurfaceFlinger::appendSfConfigString(String8& result) const
{
result.append(" [sf");
-#ifdef HAS_CONTEXT_PRIORITY
- result.append(" HAS_CONTEXT_PRIORITY");
-#endif
-#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
- result.append(" NEVER_DEFAULT_TO_ASYNC_MODE");
-#endif
+ result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
+
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
+ result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
result.append("]");
}
@@ -3127,8 +3132,8 @@
result.append("DispSync configuration: ");
colorizer.reset(result);
result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
- "present offset %d ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, dispSyncPresentTimeOffset,
mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
result.append("\n");
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index f93d918..f46ce8a 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -8,8 +8,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
- Transaction_test.cpp \
- SurfaceInterceptor_test.cpp
+ Transaction_test.cpp \
+ Stress_test.cpp \
+ SurfaceInterceptor_test.cpp
LOCAL_SHARED_LIBRARIES := \
libEGL \
@@ -20,6 +21,7 @@
libprotobuf-cpp-full \
libui \
libutils \
+ libandroid \
liblog
LOCAL_STATIC_LIBRARIES := libtrace_proto
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
new file mode 100644
index 0000000..33dd2f5
--- /dev/null
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <utils/String8.h>
+
+#include <thread>
+#include <functional>
+
+
+namespace android {
+
+TEST(SurfaceFlingerStress, create_and_destroy) {
+ auto do_stress = []() {
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, client->initCheck());
+ for (int j = 0; j < 1000; j++) {
+ auto surf = client->createSurface(String8("t"), 100, 100,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(surf != nullptr);
+ client->destroySurface(surf->getHandle());
+ }
+ };
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread(do_stress));
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 1a3f89f..0cc763c 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -15,6 +15,7 @@
*/
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <gtest/gtest.h>
@@ -68,11 +69,18 @@
}
static status_t readProtoFile(Trace* trace) {
- std::ifstream input(DEFAULT_FILENAME, std::ios::in | std::ios::binary);
- if (input && !trace->ParseFromIstream(&input)) {
- return PERMISSION_DENIED;
+ status_t err = NO_ERROR;
+
+ int fd = open(DEFAULT_FILENAME, O_RDONLY);
+ {
+ google::protobuf::io::FileInputStream f(fd);
+ if (fd && !trace->ParseFromZeroCopyStream(&f)) {
+ err = PERMISSION_DENIED;
+ }
}
- return NO_ERROR;
+ close(fd);
+
+ return err;
}
static void enableInterceptor() {
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk
index b8c2133..203ced5 100644
--- a/services/surfaceflinger/tests/hwc2/Android.mk
+++ b/services/surfaceflinger/tests/hwc2/Android.mk
@@ -40,7 +40,8 @@
LOCAL_STATIC_LIBRARIES := \
libbase \
libadf \
- libadfhwc
+ libadfhwc \
+ libmath
LOCAL_SRC_FILES := \
Hwc2Test.cpp \
Hwc2TestProperties.cpp \
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index a59f388..1d3a1d3 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -21,10 +21,9 @@
#include <gui/Surface.h>
#include <gui/BufferItemConsumer.h>
-#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBuffer.h>
-#include <ui/vec4.h>
+#include <math/vec4.h>
#include <GLES3/gl3.h>
@@ -395,15 +394,17 @@
* devices */
int Hwc2TestBuffer::generateBuffer()
{
- int ret;
-
/* Create new graphic buffer with correct dimensions */
- mGraphicBuffer = mGraphicBufferAlloc.createGraphicBuffer(
- mBufferArea.width, mBufferArea.height, mFormat,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
- "hwc2_test_buffer", &ret);
- if (ret)
+ mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+ mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
+ "hwc2_test_buffer");
+ int ret = mGraphicBuffer->initCheck();
+ if (ret) {
return ret;
+ }
+ if (!mGraphicBuffer->handle) {
+ return -EINVAL;
+ }
/* Locks the buffer for writing */
uint8_t* img;
@@ -466,15 +467,17 @@
const std::set<hwc2_layer_t>* clientLayers,
const std::set<hwc2_layer_t>* clearLayers)
{
- int err;
-
- /* Create new graphic buffer with updated size */
- mGraphicBuffer = mGraphicBufferAlloc.createGraphicBuffer(bufferArea.width,
- bufferArea.height, mFormat,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
- "hwc2_test_buffer", &err);
- if (err)
- return err;
+ /* Create new graphic buffer with correct dimensions */
+ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
+ mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
+ "hwc2_test_buffer");
+ int ret = mGraphicBuffer->initCheck();
+ if (ret) {
+ return ret;
+ }
+ if (!mGraphicBuffer->handle) {
+ return -EINVAL;
+ }
uint8_t* img;
mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
index ca60940..b2b3a66 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
@@ -22,7 +22,6 @@
#include <hardware/hwcomposer2.h>
-#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBuffer.h>
#include "Hwc2TestProperties.h"
@@ -42,7 +41,6 @@
protected:
int generateBuffer();
- android::GraphicBufferAlloc mGraphicBufferAlloc;
android::sp<android::GraphicBuffer> mGraphicBuffer;
std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
@@ -66,7 +64,6 @@
const std::set<hwc2_layer_t>* clearLayers);
protected:
- android::GraphicBufferAlloc mGraphicBufferAlloc;
android::sp<android::GraphicBuffer> mGraphicBuffer;
std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 39d6bc8..ae87acd 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -92,29 +92,39 @@
size_t producer_slot = pending_buffer_slots_.front().second;
pending_buffer_slots_.pop();
- // It's possible that the producer channel has expired.
+ // It's possible that the producer channel has expired. When this occurs,
+ // ignore the producer channel.
if (producer_channel == nullptr) {
- ALOGE(
+ ALOGW(
"ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
"channel has already been expired.");
- REPLY_ERROR_RETURN(message, ENOENT, {});
+ continue;
}
RemoteChannelHandle consumer_handle(
producer_channel->CreateConsumer(message));
- // All buffer imports should succeed together.
+ // If no buffers are imported successfully, clear available and return an
+ // error. Otherwise, return all consumer handles already imported
+ // successfully, but keep available bits on, so that the client can retry
+ // importing remaining consumer buffers.
if (!consumer_handle.valid()) {
ALOGE(
"ConsumerQueueChannel::OnConsumerQueueImportBuffers: imported "
"consumer handle is invalid.");
- REPLY_ERROR_RETURN(message, EIO, {});
+ if (buffer_handles.empty()) {
+ ClearAvailable();
+ REPLY_ERROR_RETURN(message, EIO, {});
+ } else {
+ return buffer_handles;
+ }
}
// Move consumer_handle into buffer_handles.
buffer_handles.emplace_back(std::move(consumer_handle), producer_slot);
}
+ ClearAvailable();
return buffer_handles;
}
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index b4c0a52..a4ccdd0 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -308,9 +308,8 @@
}
void EvdevInjector::dumpInternal(String8& result) {
- result.append("[injector]\n");
- result.appendFormat("state = %d\n", static_cast<int>(state_));
- result.appendFormat("error = %d\n\n", error_);
+ result.appendFormat("injector_state = %d\n", static_cast<int>(state_));
+ result.appendFormat("injector_error = %d\n", error_);
}
} // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index bc29408..92193d3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -18,7 +18,7 @@
// use it to look up device configuration, so it must be unique. Vendor and
// product values must be 0 to indicate an internal device and prevent a
// similar lookup that could conflict with a physical device.
-static const char* const kDeviceName = "vr window manager virtual touchpad";
+static const char* const kDeviceNameFormat = "vr virtual touchpad %d";
static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
static constexpr int16_t kDeviceVendor = 0;
static constexpr int16_t kDeviceProduct = 0;
@@ -32,122 +32,154 @@
sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
+ touchpad->Reset();
return sp<VirtualTouchpad>(touchpad);
}
-status_t VirtualTouchpadEvdev::Attach() {
- if (!injector_) {
- owned_injector_.reset(new EvdevInjector());
- injector_ = owned_injector_.get();
+void VirtualTouchpadEvdev::Reset() {
+ for (auto& touchpad : touchpad_) {
+ if (touchpad.injector) {
+ touchpad.injector->Close();
+ }
+ touchpad.injector = nullptr;
+ touchpad.owned_injector.reset();
+ touchpad.last_device_x = INT32_MIN;
+ touchpad.last_device_y = INT32_MIN;
+ touchpad.touches = 0;
+ touchpad.last_motion_event_buttons = 0;
}
- injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor,
- kDeviceProduct, kDeviceVersion);
- injector_->ConfigureInputProperty(INPUT_PROP_DIRECT);
- injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
- injector_->ConfigureAbsSlots(kSlots);
- injector_->ConfigureKey(BTN_TOUCH);
- injector_->ConfigureKey(BTN_BACK);
- injector_->ConfigureEnd();
- return injector_->GetError();
+}
+
+status_t VirtualTouchpadEvdev::Attach() {
+ status_t status = OK;
+ for (int i = 0; i < kTouchpads; ++i) {
+ Touchpad& touchpad = touchpad_[i];
+ if (!touchpad.injector) {
+ touchpad.owned_injector.reset(new EvdevInjector());
+ touchpad.injector = touchpad.owned_injector.get();
+ }
+ String8 DeviceName;
+ DeviceName.appendFormat(kDeviceNameFormat, i);
+ touchpad.injector->ConfigureBegin(DeviceName, kDeviceBusType,
+ kDeviceVendor, kDeviceProduct,
+ kDeviceVersion);
+ touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
+ touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
+ touchpad.injector->ConfigureAbsSlots(kSlots);
+ touchpad.injector->ConfigureKey(BTN_TOUCH);
+ touchpad.injector->ConfigureKey(BTN_BACK);
+ touchpad.injector->ConfigureEnd();
+ if (const status_t configuration_status = touchpad.injector->GetError()) {
+ status = configuration_status;
+ }
+ }
+ return status;
}
status_t VirtualTouchpadEvdev::Detach() {
- injector_->Close();
- injector_ = nullptr;
- owned_injector_.reset();
- last_device_x_ = INT32_MIN;
- last_device_y_ = INT32_MIN;
- touches_ = 0;
- last_motion_event_buttons_ = 0;
+ Reset();
return OK;
}
-int VirtualTouchpadEvdev::Touch(int touchpad, float x, float y,
+int VirtualTouchpadEvdev::Touch(int touchpad_id, float x, float y,
float pressure) {
- (void)touchpad; // TODO(b/35992608) Support multiple touchpad devices.
+ if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+ return EINVAL;
+ }
if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
return EINVAL;
}
int32_t device_x = x * kWidth;
int32_t device_y = y * kHeight;
- touches_ = ((touches_ & 1) << 1) | (pressure > 0);
+ Touchpad& touchpad = touchpad_[touchpad_id];
+ touchpad.touches = ((touchpad.touches & 1) << 1) | (pressure > 0);
ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x,
- device_y, touches_);
+ device_y, touchpad.touches);
- if (!injector_) {
+ if (!touchpad.injector) {
return EvdevInjector::ERROR_SEQUENCING;
}
- injector_->ResetError();
- switch (touches_) {
+ touchpad.injector->ResetError();
+ switch (touchpad.touches) {
case 0b00: // Hover continues.
- if (device_x != last_device_x_ || device_y != last_device_y_) {
- injector_->SendMultiTouchXY(0, 0, device_x, device_y);
- injector_->SendSynReport();
+ if (device_x != touchpad.last_device_x ||
+ device_y != touchpad.last_device_y) {
+ touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
+ touchpad.injector->SendSynReport();
}
break;
case 0b01: // Touch begins.
// Press.
- injector_->SendMultiTouchXY(0, 0, device_x, device_y);
- injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
- injector_->SendSynReport();
+ touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
+ touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
+ touchpad.injector->SendSynReport();
break;
case 0b10: // Touch ends.
- injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
- injector_->SendMultiTouchLift(0);
- injector_->SendSynReport();
+ touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
+ touchpad.injector->SendMultiTouchLift(0);
+ touchpad.injector->SendSynReport();
break;
case 0b11: // Touch continues.
- if (device_x != last_device_x_ || device_y != last_device_y_) {
- injector_->SendMultiTouchXY(0, 0, device_x, device_y);
- injector_->SendSynReport();
+ if (device_x != touchpad.last_device_x ||
+ device_y != touchpad.last_device_y) {
+ touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
+ touchpad.injector->SendSynReport();
}
break;
}
- last_device_x_ = device_x;
- last_device_y_ = device_y;
+ touchpad.last_device_x = device_x;
+ touchpad.last_device_y = device_y;
- return injector_->GetError();
+ return touchpad.injector->GetError();
}
-int VirtualTouchpadEvdev::ButtonState(int touchpad, int buttons) {
- (void)touchpad; // TODO(b/35992608) Support multiple touchpad devices.
- const int changes = last_motion_event_buttons_ ^ buttons;
+int VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) {
+ if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+ return EINVAL;
+ }
+ Touchpad& touchpad = touchpad_[touchpad_id];
+ const int changes = touchpad.last_motion_event_buttons ^ buttons;
if (!changes) {
return 0;
}
if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
return ENOTSUP;
}
- ALOGV("change %X from %X to %X", changes, last_motion_event_buttons_,
+ ALOGV("change %X from %X to %X", changes, touchpad.last_motion_event_buttons,
buttons);
- if (!injector_) {
+ if (!touchpad.injector) {
return EvdevInjector::ERROR_SEQUENCING;
}
- injector_->ResetError();
+ touchpad.injector->ResetError();
if (changes & AMOTION_EVENT_BUTTON_BACK) {
- injector_->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
- ? EvdevInjector::KEY_PRESS
- : EvdevInjector::KEY_RELEASE);
- injector_->SendSynReport();
+ touchpad.injector->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
+ ? EvdevInjector::KEY_PRESS
+ : EvdevInjector::KEY_RELEASE);
+ touchpad.injector->SendSynReport();
}
- last_motion_event_buttons_ = buttons;
- return injector_->GetError();
+ touchpad.last_motion_event_buttons = buttons;
+ return touchpad.injector->GetError();
}
void VirtualTouchpadEvdev::dumpInternal(String8& result) {
- result.append("[virtual touchpad]\n");
- if (!injector_) {
- result.append("injector = none\n");
- return;
+ for (int i = 0; i < kTouchpads; ++i) {
+ const auto& touchpad = touchpad_[i];
+ result.appendFormat("[virtual touchpad %d]\n", i);
+ if (!touchpad.injector) {
+ result.append("injector = none\n");
+ return;
+ }
+ result.appendFormat("injector = %s\n",
+ touchpad.owned_injector ? "normal" : "test");
+ result.appendFormat("touches = %d\n", touchpad.touches);
+ result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
+ touchpad.last_device_x, touchpad.last_device_y);
+ result.appendFormat("last_buttons = 0x%" PRIX32 "\n",
+ touchpad.last_motion_event_buttons);
+ touchpad.injector->dumpInternal(result);
+ result.append("\n");
}
- result.appendFormat("injector = %s\n", owned_injector_ ? "normal" : "test");
- result.appendFormat("touches = %d\n", touches_);
- result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
- last_device_x_, last_device_y_);
- result.appendFormat("last_buttons = 0x%" PRIX32 "\n\n",
- last_motion_event_buttons_);
- injector_->dumpInternal(result);
}
} // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index b158cec..dbaca9a 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -3,8 +3,8 @@
#include <memory>
-#include "VirtualTouchpad.h"
#include "EvdevInjector.h"
+#include "VirtualTouchpad.h"
namespace android {
namespace dvr {
@@ -25,31 +25,39 @@
void dumpInternal(String8& result) override;
protected:
+ static constexpr int kTouchpads = 2;
+
VirtualTouchpadEvdev() {}
~VirtualTouchpadEvdev() override {}
+ void Reset();
- // Must be called only between construction and Attach().
- inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
- injector_ = injector;
+ // Must be called only between construction (or Detach()) and Attach().
+ inline void SetEvdevInjectorForTesting(int touchpad,
+ EvdevInjector* injector) {
+ touchpad_[touchpad].injector = injector;
}
private:
- // Except for testing, the |EvdevInjector| used to inject evdev events.
- std::unique_ptr<EvdevInjector> owned_injector_;
+ // Per-touchpad state.
+ struct Touchpad {
+ // Except for testing, the |EvdevInjector| used to inject evdev events.
+ std::unique_ptr<EvdevInjector> owned_injector;
- // Active pointer to |owned_injector_| or to a testing injector.
- EvdevInjector* injector_ = nullptr;
+ // Active pointer to |owned_injector_| or to a testing injector.
+ EvdevInjector* injector = nullptr;
- // Previous (x, y) position in device space, to suppress redundant events.
- int32_t last_device_x_ = INT32_MIN;
- int32_t last_device_y_ = INT32_MIN;
+ // Previous (x, y) position in device space, to suppress redundant events.
+ int32_t last_device_x;
+ int32_t last_device_y;
- // Records current touch state (0=up 1=down) in bit 0, and previous state
- // in bit 1, to track transitions.
- int touches_ = 0;
+ // Records current touch state (0=up 1=down) in bit 0, and previous state
+ // in bit 1, to track transitions.
+ int touches;
- // Previous injected button state, to detect changes.
- int32_t last_motion_event_buttons_ = 0;
+ // Previous injected button state, to detect changes.
+ int32_t last_motion_event_buttons;
+ };
+ Touchpad touchpad_[kTouchpads];
VirtualTouchpadEvdev(const VirtualTouchpadEvdev&) = delete;
void operator=(const VirtualTouchpadEvdev&) = delete;
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index b11a983..bc34850 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -88,17 +88,24 @@
class EvdevInjectorForTesting : public EvdevInjector {
public:
- EvdevInjectorForTesting(UInput& uinput) { SetUInputForTesting(&uinput); }
+ EvdevInjectorForTesting() { SetUInputForTesting(&record); }
const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
+ UInputRecorder record;
};
class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
public:
- static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
+ static sp<VirtualTouchpad> Create() { return sp<VirtualTouchpad>(New()); }
+ static VirtualTouchpadForTesting* New() {
VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
- touchpad->SetEvdevInjectorForTesting(&injector);
- return sp<VirtualTouchpad>(touchpad);
+ touchpad->Reset();
+ for (int t = 0; t < kTouchpads; ++t) {
+ touchpad->SetEvdevInjectorForTesting(t, &touchpad->injector[t]);
+ }
+ return touchpad;
}
+ int GetTouchpadCount() const { return kTouchpads; }
+ EvdevInjectorForTesting injector[kTouchpads];
};
void DumpDifference(const char* expect, const char* actual) {
@@ -117,133 +124,169 @@
class VirtualTouchpadTest : public testing::Test {};
TEST_F(VirtualTouchpadTest, Goodness) {
+ sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
UInputRecorder expect;
- UInputRecorder record;
- EvdevInjectorForTesting injector(record);
- sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
status_t touch_status = touchpad->Attach();
EXPECT_EQ(0, touch_status);
// Check some aspects of uinput_user_dev.
- const uinput_user_dev* uidev = injector.GetUiDev();
- for (int i = 0; i < ABS_CNT; ++i) {
- EXPECT_EQ(0, uidev->absmin[i]);
- EXPECT_EQ(0, uidev->absfuzz[i]);
- EXPECT_EQ(0, uidev->absflat[i]);
- if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y && i != ABS_MT_SLOT) {
- EXPECT_EQ(0, uidev->absmax[i]);
+ const uinput_user_dev* uidev;
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ uidev = touchpad->injector[t].GetUiDev();
+ String8 name;
+ name.appendFormat("vr virtual touchpad %d", t);
+ EXPECT_EQ(name, uidev->name);
+ for (int i = 0; i < ABS_CNT; ++i) {
+ EXPECT_EQ(0, uidev->absmin[i]);
+ EXPECT_EQ(0, uidev->absfuzz[i]);
+ EXPECT_EQ(0, uidev->absflat[i]);
+ if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y &&
+ i != ABS_MT_SLOT) {
+ EXPECT_EQ(0, uidev->absmax[i]);
+ }
}
}
const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
const int32_t slots = uidev->absmax[ABS_MT_SLOT];
- // Check the system calls performed by initialization.
- // From ConfigureBegin():
- expect.Open();
- // From ConfigureInputProperty(INPUT_PROP_DIRECT):
- expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
- // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
- expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
- expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
- expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
- // From ConfigureAbsSlots(kSlots):
- expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
- // From ConfigureKey(BTN_TOUCH):
- expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
- expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
- expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
- // From ConfigureEnd():
- expect.Write(uidev, sizeof(uinput_user_dev));
- expect.IoctlVoid(UI_DEV_CREATE);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ // Check the system calls performed by initialization.
+ expect.Reset();
+ // From ConfigureBegin():
+ expect.Open();
+ // From ConfigureInputProperty(INPUT_PROP_DIRECT):
+ expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
+ // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
+ expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
+ expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
+ expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
+ // From ConfigureAbsSlots(kSlots):
+ expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+ // From ConfigureKey(BTN_TOUCH):
+ expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
+ expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
+ expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
+ // From ConfigureEnd():
+ expect.Write(touchpad->injector[t].GetUiDev(), sizeof(uinput_user_dev));
+ expect.IoctlVoid(UI_DEV_CREATE);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0, 0, 0);
- EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->Touch(t, 0, 0, 0);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 0.75f, 0.5f);
- EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->Touch(t, 0.25f, 0.75f, 0.5f);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.99f, 0.99f, 0.99f);
- EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->Touch(t, 0.99f, 0.99f, 0.99f);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.0f, 1.0f, 1.0f);
- EXPECT_EQ(EINVAL, touch_status);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->Touch(t, 1.0f, 1.0f, 1.0f);
+ EXPECT_EQ(EINVAL, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status =
- touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 0.75f, -0.01f);
- EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->Touch(t, 0.25f, 0.75f, -0.01f);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
- AMOTION_EVENT_BUTTON_BACK);
- EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
- AMOTION_EVENT_BUTTON_BACK);
- EXPECT_EQ(0, touch_status);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
- touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY, 0);
- EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ touch_status = touchpad->ButtonState(t, 0);
+ EXPECT_EQ(0, touch_status);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
expect.Reset();
- record.Reset();
+ expect.Close();
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ touchpad->injector[t].record.Reset();
+ }
touch_status = touchpad->Detach();
EXPECT_EQ(0, touch_status);
- expect.Close();
- EXPECT_EQ(expect.GetString(), record.GetString());
+ for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
+ SCOPED_TRACE(t);
+ EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
+ }
}
TEST_F(VirtualTouchpadTest, Badness) {
+ sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
UInputRecorder expect;
- UInputRecorder record;
- EvdevInjectorForTesting injector(record);
- sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
+ UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
status_t touch_status = touchpad->Attach();
EXPECT_EQ(0, touch_status);
@@ -252,11 +295,9 @@
// and should not result in any system calls.
expect.Reset();
record.Reset();
- touch_status =
- touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
+ touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
EXPECT_NE(OK, touch_status);
- touch_status =
- touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
+ touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
EXPECT_NE(OK, touch_status);
touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f);
EXPECT_NE(OK, touch_status);
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index ddb58e9..59ef63c 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -17,6 +17,7 @@
native_src := \
application.cpp \
controller_mesh.cpp \
+ display_view.cpp \
elbow_model.cpp \
hwc_callback.cpp \
reticle.cpp \
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 24087c9..eb9f407 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -224,6 +224,8 @@
DrawEye(kRightEye, fov_[kRightEye].GetProjectionMatrix(0.1f, 500.0f),
eye_from_head_[kRightEye], head_matrix);
+ OnEndFrame();
+
dvrPresent(graphics_context_);
}
}
@@ -294,10 +296,7 @@
bool changed = is_visible_ != visible;
if (changed) {
is_visible_ = visible;
- // TODO (alexst): b/36036583 Disable vr_wm visibility until we figure out
- // why it's always on top. Still make it visible in debug mode.
- if (debug_mode_)
- dvrGraphicsSurfaceSetVisible(graphics_context_, is_visible_);
+ dvrGraphicsSurfaceSetVisible(graphics_context_, is_visible_);
OnVisibilityChanged(is_visible_);
}
}
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 2c60e0a..6215561 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -57,6 +57,7 @@
virtual void OnDrawFrame() = 0;
virtual void DrawEye(EyeType eye, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix) = 0;
+ virtual void OnEndFrame() = 0;
void SetVisibility(bool visible);
virtual void OnVisibilityChanged(bool visible);
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 6a78c98..8b50c01 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -102,7 +102,8 @@
HwcLayer* HwcDisplay::GetLayer(Layer id) {
for (size_t i = 0; i < layers_.size(); ++i)
- if (layers_[i].info.id == id) return &layers_[i];
+ if (layers_[i].info.id == id)
+ return &layers_[i];
return nullptr;
}
@@ -219,7 +220,7 @@
////////////////////////////////////////////////////////////////////////////////
// VrHwcClient
-VrHwc::VrHwc() {}
+VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); }
VrHwc::~VrHwc() {}
@@ -231,7 +232,6 @@
}
void VrHwc::enableCallback(bool enable) {
- std::lock_guard<std::mutex> guard(mutex_);
if (enable && client_ != nullptr) {
client_.promote()->onHotplug(kDefaultDisplayId,
IComposerCallback::Connection::CONNECTED);
@@ -247,31 +247,43 @@
return Error::NONE;
}
-Error VrHwc::destroyVirtualDisplay(Display display) { return Error::NONE; }
+Error VrHwc::destroyVirtualDisplay(Display display) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (display == kDefaultDisplayId || displays_.erase(display) == 0)
+ return Error::BAD_DISPLAY;
+ ComposerView::Frame frame;
+ frame.display_id = display;
+ frame.removed = true;
+ if (observer_)
+ observer_->OnNewFrame(frame);
+ return Error::NONE;
+}
Error VrHwc::createLayer(Display display, Layer* outLayer) {
- if (display != kDefaultDisplayId) {
- return Error::BAD_DISPLAY;
- }
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* layer = display_.CreateLayer();
+ HwcLayer* layer = display_ptr->CreateLayer();
*outLayer = layer->info.id;
return Error::NONE;
}
Error VrHwc::destroyLayer(Display display, Layer layer) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr) {
+ return Error::BAD_DISPLAY;
+ }
- return display_.DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+ return display_ptr->DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
}
Error VrHwc::getActiveConfig(Display display, Config* outConfig) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
*outConfig = kDefaultConfigId;
return Error::NONE;
}
@@ -291,20 +303,19 @@
Error VrHwc::getDisplayAttribute(Display display, Config config,
IComposerClient::Attribute attribute,
int32_t* outValue) {
- if (display != kDefaultDisplayId) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
return Error::BAD_DISPLAY;
- }
-
if (config != kDefaultConfigId) {
return Error::BAD_CONFIG;
}
switch (attribute) {
case IComposerClient::Attribute::WIDTH:
- *outValue = 1920;
+ *outValue = 1080;
break;
case IComposerClient::Attribute::HEIGHT:
- *outValue = 1080;
+ *outValue = 1920;
break;
case IComposerClient::Attribute::VSYNC_PERIOD:
*outValue = 1000 * 1000 * 1000 / 30; // 30fps
@@ -321,10 +332,9 @@
}
Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
- if (display != kDefaultDisplayId) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
return Error::BAD_DISPLAY;
- }
-
std::vector<Config> configs(1, kDefaultConfigId);
*outConfigs = hidl_vec<Config>(configs);
return Error::NONE;
@@ -337,7 +347,9 @@
Error VrHwc::getDisplayType(Display display,
IComposerClient::DisplayType* outType) {
- if (display != kDefaultDisplayId) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr) {
*outType = IComposerClient::DisplayType::INVALID;
return Error::BAD_DISPLAY;
}
@@ -348,10 +360,10 @@
Error VrHwc::getDozeSupport(Display display, bool* outSupport) {
*outSupport = false;
- if (display == kDefaultDisplayId)
- return Error::NONE;
- else
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
return Error::BAD_DISPLAY;
+ return Error::NONE;
}
Error VrHwc::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
@@ -365,35 +377,41 @@
}
Error VrHwc::setActiveConfig(Display display, Config config) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
- if (config != kDefaultConfigId) return Error::BAD_CONFIG;
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
+ if (config != kDefaultConfigId)
+ return Error::BAD_CONFIG;
return Error::NONE;
}
Error VrHwc::setColorMode(Display display, ColorMode mode) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setColorTransform(Display display, const float* matrix,
int32_t hint) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
@@ -401,13 +419,15 @@
int32_t acquireFence, int32_t dataspace,
const std::vector<hwc_rect_t>& damage) {
base::unique_fd fence(acquireFence);
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
- if (target == nullptr) return Error::NONE;
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- if (!display_.SetClientTarget(target, std::move(fence)))
+ if (target == nullptr)
+ return Error::NONE;
+
+ if (!display_ptr->SetClientTarget(target, std::move(fence)))
return Error::BAD_PARAMETER;
return Error::NONE;
@@ -416,7 +436,10 @@
Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer,
int32_t releaseFence) {
base::unique_fd fence(releaseFence);
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
ALOGE("Virtual display support not implemented");
return Error::UNSUPPORTED;
@@ -427,13 +450,13 @@
std::vector<IComposerClient::Composition>* outCompositionTypes,
uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
std::vector<uint32_t>* outRequestMasks) {
- if (display != kDefaultDisplayId) {
- return Error::BAD_DISPLAY;
- }
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- display_.GetChangedCompositionTypes(outChangedLayers, outCompositionTypes);
+ display_ptr->GetChangedCompositionTypes(outChangedLayers,
+ outCompositionTypes);
return Error::NONE;
}
@@ -446,18 +469,20 @@
outLayers->clear();
outReleaseFences->clear();
- if (display != kDefaultDisplayId) {
- return Error::BAD_DISPLAY;
- }
-
- std::vector<ComposerView::ComposerLayer> frame;
- std::vector<Layer> last_frame_layers;
std::lock_guard<std::mutex> guard(mutex_);
- Error status = display_.GetFrame(&frame);
+ auto display_ptr = FindDisplay(display);
+
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
+
+ ComposerView::Frame frame;
+ std::vector<Layer> last_frame_layers;
+ Error status = display_ptr->GetFrame(&frame.layers);
+ frame.display_id = display;
if (status != Error::NONE)
return status;
- last_frame_layers = display_.UpdateLastFrameAndGetLastFrameLayers();
+ last_frame_layers = display_ptr->UpdateLastFrameAndGetLastFrameLayers();
base::unique_fd fence;
if (observer_)
@@ -476,18 +501,23 @@
Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x,
int32_t y) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerBuffer(Display display, Layer layer,
buffer_handle_t buffer, int32_t acquireFence) {
base::unique_fd fence(acquireFence);
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.buffer = GetBufferFromHandle(buffer);
hwc_layer->info.fence = new Fence(fence.release());
@@ -497,16 +527,21 @@
Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<hwc_rect_t>& damage) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerBlendMode(Display display, Layer layer, int32_t mode) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.blend_mode =
static_cast<ComposerView::ComposerLayer::BlendMode>(mode);
@@ -516,17 +551,22 @@
Error VrHwc::setLayerColor(Display display, Layer layer,
IComposerClient::Color color) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerCompositionType(Display display, Layer layer,
int32_t type) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->composition_type = static_cast<HwcLayer::Composition>(type);
@@ -535,17 +575,22 @@
Error VrHwc::setLayerDataspace(Display display, Layer layer,
int32_t dataspace) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerDisplayFrame(Display display, Layer layer,
const hwc_rect_t& frame) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.display_frame =
{frame.left, frame.top, frame.right, frame.bottom};
@@ -554,10 +599,14 @@
}
Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.alpha = alpha;
@@ -566,17 +615,22 @@
Error VrHwc::setLayerSidebandStream(Display display, Layer layer,
buffer_handle_t stream) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerSourceCrop(Display display, Layer layer,
const hwc_frect_t& crop) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.crop = {crop.left, crop.top, crop.right, crop.bottom};
@@ -585,23 +639,29 @@
Error VrHwc::setLayerTransform(Display display, Layer layer,
int32_t transform) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerVisibleRegion(Display display, Layer layer,
const std::vector<hwc_rect_t>& visible) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerZOrder(Display display, Layer layer, uint32_t z) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->z_order = z;
@@ -610,10 +670,14 @@
Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type,
uint32_t appId) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.type = type;
hwc_layer->info.app_id = appId;
@@ -665,6 +729,11 @@
observer_ = nullptr;
}
+HwcDisplay* VrHwc::FindDisplay(Display display) {
+ auto iter = displays_.find(display);
+ return iter == displays_.end() ? nullptr : iter->second.get();
+}
+
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 df09687..b869d3e 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -24,6 +24,7 @@
#include <utils/StrongPointer.h>
#include <mutex>
+#include <unordered_map>
using namespace android::hardware::graphics::common::V1_0;
using namespace android::hardware::graphics::composer::V2_1;
@@ -67,7 +68,14 @@
uint32_t app_id;
};
- using Frame = std::vector<ComposerLayer>;
+ struct Frame {
+ Display display_id;
+ // This is set to true to notify the upper layer that the display is
+ // being removed, or left false in the case of a normal frame. The upper
+ // layer tracks display IDs and will handle new ones showing up.
+ bool removed = false;
+ std::vector<ComposerLayer> layers;
+ };
class Observer {
public:
@@ -231,13 +239,15 @@
void UnregisterObserver(Observer* observer) override;
private:
+ HwcDisplay* FindDisplay(Display display);
+
wp<VrComposerClient> client_;
sp<IComposerCallback> callbacks_;
// Guard access to internal state from binder threads.
std::mutex mutex_;
- HwcDisplay display_;
+ std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
Observer* observer_ = nullptr;
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
new file mode 100644
index 0000000..5f1e73e
--- /dev/null
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -0,0 +1,432 @@
+#include "display_view.h"
+
+#include "texture.h"
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+constexpr float kLayerScaleFactor = 3.0f;
+constexpr unsigned int kVRAppLayerCount = 2;
+constexpr unsigned int kMaximumPendingFrames = 8;
+
+// clang-format off
+const GLfloat kVertices[] = {
+ -1, -1, 0,
+ 1, -1, 0,
+ -1, 1, 0,
+ 1, 1, 0,
+};
+
+const GLfloat kTextureVertices[] = {
+ 0, 1,
+ 1, 1,
+ 0, 0,
+ 1, 0,
+};
+// clang-format on
+
+// Returns true if the given point is inside the given rect.
+bool IsInside(const vec2& pt, const vec2& tl, const vec2& br) {
+ return pt.x() >= tl.x() && pt.x() <= br.x() && pt.y() >= tl.y() &&
+ pt.y() <= br.y();
+}
+
+mat4 GetScalingMatrix(float width, float height) {
+ float xscale = 1, yscale = 1;
+ float ar = width / height;
+ if (ar > 1)
+ yscale = 1.0 / ar;
+ else
+ xscale = ar;
+
+ xscale *= kLayerScaleFactor;
+ yscale *= kLayerScaleFactor;
+
+ return mat4(Eigen::Scaling<float>(xscale, yscale, 1.0));
+}
+
+// Helper function that applies the crop transform to the texture layer and
+// positions (and scales) the texture layer in the appropriate location in the
+// display space.
+mat4 GetLayerTransform(const TextureLayer& texture_layer, float display_width,
+ float display_height) {
+ // Map from vertex coordinates to [0, 1] coordinates:
+ // 1) Flip y since in vertex coordinates (-1, -1) is at the bottom left and
+ // in texture coordinates (0, 0) is at the top left.
+ // 2) Translate by (1, 1) to map vertex coordinates to [0, 2] on x and y.
+ // 3) Scale by 1 / 2 to map coordinates to [0, 1] on x and y.
+ mat4 unit_space(Eigen::AlignedScaling3f(0.5f, 0.5f, 1.0f) *
+ Eigen::Translation3f(1.0f, 1.0f, 0.0f) *
+ Eigen::AlignedScaling3f(1.0f, -1.0f, 1.0f));
+
+ mat4 texture_space(Eigen::AlignedScaling3f(
+ texture_layer.texture->width(), texture_layer.texture->height(), 1.0f));
+
+ // 1) Translate the layer to crop the left and top edge.
+ // 2) Scale the layer such that the cropped right and bottom edges map outside
+ // the exture region.
+ float crop_width = texture_layer.crop.right - texture_layer.crop.left;
+ float crop_height = texture_layer.crop.bottom - texture_layer.crop.top;
+ mat4 texture_crop(Eigen::AlignedScaling3f(
+ texture_layer.texture->width() / crop_width,
+ texture_layer.texture->height() / crop_height, 1.0f) *
+ Eigen::Translation3f(-texture_layer.crop.left,
+ -texture_layer.crop.top, 0.0f));
+
+ mat4 display_space(
+ Eigen::AlignedScaling3f(display_width, display_height, 1.0f));
+
+ // 1) Scale the texture to fit the display frame.
+ // 2) Translate the texture in the display frame location.
+ float display_frame_width =
+ texture_layer.display_frame.right - texture_layer.display_frame.left;
+ float display_frame_height =
+ texture_layer.display_frame.bottom - texture_layer.display_frame.top;
+ mat4 display_frame(
+ Eigen::Translation3f(texture_layer.display_frame.left,
+ texture_layer.display_frame.top, 0.0f) *
+ Eigen::AlignedScaling3f(display_frame_width / display_width,
+ display_frame_height / display_height, 1.0f));
+
+ mat4 layer_transform = unit_space.inverse() * display_space.inverse() *
+ display_frame * display_space *
+ texture_space.inverse() * texture_crop *
+ texture_space * unit_space;
+ return layer_transform;
+}
+
+// Determine if ths frame should be shown or hidden.
+ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
+ uint32_t vr_app) {
+ auto& layers = frame.layers();
+
+ // TODO(achaulk): Figure out how to identify the current VR app for 2D app
+ // detection.
+
+ size_t index;
+ // Skip all layers that we don't know about.
+ for (index = 0; index < layers.size(); index++) {
+ if (layers[index].type != 0xFFFFFFFF && layers[index].type != 0)
+ break;
+ }
+
+ if (index == layers.size())
+ return ViewMode::Hidden;
+
+ if (layers[index].type != 1) {
+ // We don't have a VR app layer? Abort.
+ return ViewMode::Hidden;
+ }
+
+ // This is the VR app, ignore it.
+ index++;
+
+ // Now, find a dim layer if it exists.
+ // If it does, ignore any layers behind it for visibility determination.
+ for (size_t i = index; i < layers.size(); i++) {
+ if (layers[i].appid == HwcCallback::HwcLayer::kSurfaceFlingerLayer) {
+ index = i + 1;
+ }
+ }
+
+ // If any non-skipped layers exist now then we show, otherwise hide.
+ for (size_t i = index; i < layers.size(); i++) {
+ if (!layers[i].should_skip_layer())
+ return ViewMode::VR;
+ }
+ return ViewMode::Hidden;
+}
+
+} // namespace
+
+DisplayView::DisplayView(uint32_t id, int touchpad_id)
+ : id_(id), touchpad_id_(touchpad_id) {
+ translate_ = Eigen::Translation3f(0, 0, -2.5f);
+ ime_translate_ = mat4(Eigen::Translation3f(0.0f, -0.5f, 0.25f));
+ ime_top_left_ = vec2(0, 0);
+ ime_size_ = vec2(0, 0);
+}
+
+DisplayView::~DisplayView() {}
+
+void DisplayView::Recenter(const mat4& initial) {
+ initial_head_matrix_ = initial;
+}
+
+void DisplayView::SetPrograms(ShaderProgram* program,
+ ShaderProgram* overlay_program) {
+ program_ = program;
+ overlay_program_ = overlay_program;
+}
+
+void DisplayView::DrawEye(EyeType /* eye */, const mat4& perspective,
+ const mat4& eye_matrix, const mat4& head_matrix,
+ const vec2& size, float fade_value) {
+ size_ = size;
+ scale_ = GetScalingMatrix(size_.x(), size_.y());
+
+ DrawOverlays(perspective, eye_matrix, head_matrix, fade_value);
+}
+
+void DisplayView::AdvanceFrame() {
+ if (!pending_frames_.empty()) {
+ // Check if we should advance the frame.
+ auto& frame = pending_frames_.front();
+ if (frame.visibility == ViewMode::Hidden ||
+ frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
+ current_frame_ = std::move(frame);
+ pending_frames_.pop_front();
+ }
+ }
+}
+
+void DisplayView::OnDrawFrame(SurfaceFlingerView* surface_flinger_view,
+ bool debug_mode) {
+ textures_.clear();
+ has_ime_ = false;
+
+ if (!visible())
+ return;
+
+ surface_flinger_view->GetTextures(*current_frame_.frame.get(), &textures_,
+ &ime_texture_, debug_mode,
+ current_frame_.visibility == ViewMode::VR);
+ has_ime_ = ime_texture_.texture != nullptr;
+}
+
+base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
+ bool debug_mode, bool* showing) {
+ ViewMode visibility =
+ CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
+
+ if (visibility == ViewMode::Hidden && debug_mode)
+ visibility = ViewMode::VR;
+
+ if (frame->layers().empty())
+ current_vr_app_ = 0;
+ else
+ current_vr_app_ = frame->layers().front().appid;
+
+ pending_frames_.emplace_back(std::move(frame), visibility);
+
+ if (pending_frames_.size() > kMaximumPendingFrames) {
+ pending_frames_.pop_front();
+ }
+
+ if (visibility == ViewMode::Hidden &&
+ current_frame_.visibility == ViewMode::Hidden) {
+ // Consume all frames while hidden.
+ while (!pending_frames_.empty())
+ AdvanceFrame();
+ }
+
+ // If we are showing ourselves the main thread is not processing anything,
+ // so give it a kick.
+ if (visibility != ViewMode::Hidden &&
+ current_frame_.visibility == ViewMode::Hidden) {
+ *showing = true;
+ }
+
+ return base::unique_fd(dup(release_fence_.get()));
+}
+
+bool DisplayView::IsHit(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location, vec2* hit_location_in_window_coord,
+ bool test_ime) {
+ mat4 m = initial_head_matrix_ * translate_;
+ if (test_ime)
+ m = m * ime_translate_;
+ mat4 inverse = (m * scale_).inverse();
+ vec4 transformed_loc =
+ inverse * vec4(view_location[0], view_location[1], view_location[2], 1);
+ vec4 transformed_dir = inverse * vec4(view_direction[0], view_direction[1],
+ view_direction[2], 0);
+
+ if (transformed_dir.z() >= 0 || transformed_loc.z() <= 0)
+ return false;
+
+ float distance = -transformed_loc.z() / transformed_dir.z();
+ vec4 transformed_hit_loc = transformed_loc + transformed_dir * distance;
+ if (transformed_hit_loc.x() < -1 || transformed_hit_loc.x() > 1)
+ return false;
+ if (transformed_hit_loc.y() < -1 || transformed_hit_loc.y() > 1)
+ return false;
+
+ hit_location_in_window_coord->x() =
+ (1 + transformed_hit_loc.x()) / 2 * size_.x();
+ hit_location_in_window_coord->y() =
+ (1 - transformed_hit_loc.y()) / 2 * size_.y();
+
+ *hit_location = view_location + view_direction * distance;
+ return true;
+}
+
+void DisplayView::DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
+ const mat4& head_matrix, float fade_value) {
+ if (textures_.empty())
+ return;
+
+ program_->Use();
+ mat4 mvp = perspective * eye_matrix * head_matrix;
+ GLint view_projection_location =
+ glGetUniformLocation(program_->GetProgram(), "uViewProjection");
+ glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data());
+
+ GLint alpha_location = glGetUniformLocation(program_->GetProgram(), "uAlpha");
+
+ GLint tex_location = glGetUniformLocation(program_->GetProgram(), "tex");
+ glUniform1i(tex_location, 0);
+ glActiveTexture(GL_TEXTURE0);
+
+ for (const auto& texture_layer : textures_) {
+ switch (texture_layer.blending) {
+ case HWC2_BLEND_MODE_PREMULTIPLIED:
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ case HWC2_BLEND_MODE_COVERAGE:
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ default:
+ break;
+ }
+
+ glUniform1f(alpha_location, fade_value * texture_layer.alpha);
+
+ glBindTexture(GL_TEXTURE_2D, texture_layer.texture->id());
+
+ mat4 layer_transform =
+ GetLayerTransform(texture_layer, size_.x(), size_.y());
+
+ mat4 transform =
+ initial_head_matrix_ * translate_ * scale_ * layer_transform;
+ DrawWithTransform(transform, *program_);
+
+ glDisable(GL_BLEND);
+ }
+
+ if (has_ime_) {
+ ime_top_left_ = vec2(static_cast<float>(ime_texture_.display_frame.left),
+ static_cast<float>(ime_texture_.display_frame.top));
+ ime_size_ = vec2(static_cast<float>(ime_texture_.display_frame.right -
+ ime_texture_.display_frame.left),
+ static_cast<float>(ime_texture_.display_frame.bottom -
+ ime_texture_.display_frame.top));
+
+ DrawDimOverlay(mvp, textures_[0], ime_top_left_, ime_top_left_ + ime_size_);
+
+ DrawIme();
+ }
+}
+
+void DisplayView::UpdateReleaseFence() {
+ 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);
+ release_fence_ = std::move(fence);
+ } else {
+ ALOGE("Failed to create sync fence");
+ release_fence_ = base::unique_fd();
+ }
+}
+
+void DisplayView::DrawIme() {
+ program_->Use();
+ glBindTexture(GL_TEXTURE_2D, ime_texture_.texture->id());
+
+ mat4 layer_transform = GetLayerTransform(ime_texture_, size_.x(), size_.y());
+
+ mat4 transform = initial_head_matrix_ * translate_ * ime_translate_ * scale_ *
+ layer_transform;
+
+ DrawWithTransform(transform, *program_);
+}
+
+void DisplayView::DrawDimOverlay(const mat4& mvp, const TextureLayer& layer,
+ const vec2& top_left,
+ const vec2& bottom_right) {
+ overlay_program_->Use();
+ glUniformMatrix4fv(
+ glGetUniformLocation(overlay_program_->GetProgram(), "uViewProjection"),
+ 1, 0, mvp.data());
+ glUniform4f(glGetUniformLocation(overlay_program_->GetProgram(), "uCoords"),
+ top_left.x() / size_.x(), top_left.y() / size_.y(),
+ bottom_right.x() / size_.x(), bottom_right.y() / size_.y());
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ mat4 layer_transform = GetLayerTransform(layer, size_.x(), size_.y());
+
+ mat4 transform = initial_head_matrix_ * translate_ * scale_ * layer_transform;
+ DrawWithTransform(transform, *overlay_program_);
+ glDisable(GL_BLEND);
+}
+
+void DisplayView::DrawWithTransform(const mat4& transform,
+ const ShaderProgram& program) {
+ GLint transform_location =
+ glGetUniformLocation(program.GetProgram(), "uTransform");
+ glUniformMatrix4fv(transform_location, 1, 0, transform.data());
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, kVertices);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kTextureVertices);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+bool DisplayView::UpdateHitInfo(const vec3& view_location,
+ const vec3& view_direction,
+ vec3* hit_location) {
+ bool is_hit = false;
+ if (has_ime_) {
+ // This will set allow_input_ and hit_location_in_window_coord_.
+ is_hit = IsImeHit(view_location, view_direction, hit_location);
+ } else {
+ is_hit = IsHit(view_location, view_direction, hit_location,
+ &hit_location_in_window_coord_, false);
+ allow_input_ = is_hit;
+ }
+ return is_hit;
+}
+
+bool DisplayView::IsImeHit(const vec3& view_location,
+ const vec3& view_direction, vec3* hit_location) {
+ // First, check if the IME window is hit.
+ bool is_hit = IsHit(view_location, view_direction, hit_location,
+ &hit_location_in_window_coord_, true);
+ if (is_hit) {
+ // If it is, check if the window coordinate is in the IME region;
+ // if so then we are done.
+ if (IsInside(hit_location_in_window_coord_, ime_top_left_,
+ ime_top_left_ + ime_size_)) {
+ allow_input_ = true;
+ return true;
+ }
+ }
+
+ allow_input_ = false;
+ // Check if we have hit the main window.
+ is_hit = IsHit(view_location, view_direction, hit_location,
+ &hit_location_in_window_coord_, false);
+ if (is_hit) {
+ // Only allow input if we are not hitting the region hidden by the IME.
+ // Allowing input here would cause clicks on the main window to actually
+ // be clicks on the IME.
+ if (!IsInside(hit_location_in_window_coord_, ime_top_left_,
+ ime_top_left_ + ime_size_)) {
+ allow_input_ = true;
+ }
+ }
+ return is_hit;
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
new file mode 100644
index 0000000..0a27781
--- /dev/null
+++ b/services/vr/vr_window_manager/display_view.h
@@ -0,0 +1,107 @@
+#ifndef VR_WINDOW_MANAGER_DISPLAY_VIEW_H_
+#define VR_WINDOW_MANAGER_DISPLAY_VIEW_H_
+
+#include <private/dvr/graphics/mesh.h>
+#include <private/dvr/graphics/shader_program.h>
+
+#include "hwc_callback.h"
+#include "surface_flinger_view.h"
+
+namespace android {
+namespace dvr {
+
+enum class ViewMode {
+ Hidden,
+ VR,
+ App,
+};
+
+class DisplayView {
+ public:
+ DisplayView(uint32_t id, int touchpad_id);
+ ~DisplayView();
+
+ // Calls to these 3 functions must be synchronized.
+ base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
+ bool debug_mode, bool* showing);
+ void AdvanceFrame();
+ void UpdateReleaseFence();
+
+ void OnDrawFrame(SurfaceFlingerView* surface_flinger_view, bool debug_mode);
+ void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
+ const mat4& head_matrix, const vec2& size, float fade_value);
+
+ void Recenter(const mat4& initial);
+
+ bool UpdateHitInfo(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location);
+
+ void SetPrograms(ShaderProgram* program, ShaderProgram* overlay_program);
+
+ bool visible() const { return current_frame_.visibility != ViewMode::Hidden; }
+ bool allow_input() const { return allow_input_; }
+ const vec2& hit_location() const { return hit_location_in_window_coord_; }
+ uint32_t id() const { return id_; }
+ int touchpad_id() const { return touchpad_id_; }
+
+ private:
+ bool IsHit(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location, vec2* hit_location_in_window_coord,
+ bool test_ime);
+ bool IsImeHit(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location);
+ void DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
+ const mat4& head_matrix, float fade_value);
+ void DrawIme();
+ void DrawDimOverlay(const mat4& mvp, const TextureLayer& layer,
+ const vec2& top_left, const vec2& bottom_right);
+ void DrawWithTransform(const mat4& transform, const ShaderProgram& program);
+
+ uint32_t id_;
+ int touchpad_id_;
+
+ uint32_t current_vr_app_;
+
+ ShaderProgram* program_;
+ ShaderProgram* overlay_program_;
+
+ mat4 initial_head_matrix_;
+ mat4 scale_;
+ mat4 translate_;
+ mat4 ime_translate_;
+ vec2 size_;
+
+ std::vector<TextureLayer> textures_;
+ TextureLayer ime_texture_;
+
+ bool allow_input_ = false;
+ vec2 hit_location_in_window_coord_;
+ vec2 ime_top_left_;
+ vec2 ime_size_;
+ bool has_ime_ = false;
+
+ struct PendingFrame {
+ PendingFrame() = default;
+ PendingFrame(std::unique_ptr<HwcCallback::Frame>&& frame,
+ ViewMode visibility)
+ : frame(std::move(frame)), visibility(visibility) {}
+ PendingFrame(PendingFrame&& r)
+ : frame(std::move(r.frame)), visibility(r.visibility) {}
+
+ void operator=(PendingFrame&& r) {
+ frame.reset(r.frame.release());
+ visibility = r.visibility;
+ }
+
+ std::unique_ptr<HwcCallback::Frame> frame;
+ ViewMode visibility = ViewMode::Hidden;
+ };
+ std::deque<PendingFrame> pending_frames_;
+ PendingFrame current_frame_;
+ base::unique_fd release_fence_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // VR_WINDOW_MANAGER_DISPLAY_VIEW_H_
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 05ec64a..b755c60 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,7 +38,8 @@
HwcCallback::~HwcCallback() {
}
-base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
+base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& display_frame) {
+ auto& frame = display_frame.layers;
std::vector<HwcLayer> hwc_frame(frame.size());
for (size_t i = 0; i < frame.size(); ++i) {
hwc_frame[i] = HwcLayer{
@@ -53,12 +54,13 @@
};
}
- return client_->OnFrame(
- std::make_unique<Frame>(std::move(hwc_frame)));
+ return client_->OnFrame(std::make_unique<Frame>(
+ std::move(hwc_frame), display_frame.display_id, display_frame.removed));
}
-HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers)
- : layers_(std::move(layers)) {}
+HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
+ bool removed)
+ : display_id_(display_id), removed_(removed), layers_(std::move(layers)) {}
HwcCallback::FrameStatus HwcCallback::Frame::Finish() {
if (status_ == FrameStatus::kUnfinished)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index be56856..b8aa51b 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -81,12 +81,16 @@
class Frame {
public:
- Frame(std::vector<HwcLayer>&& layers);
+ Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed);
FrameStatus Finish();
const std::vector<HwcLayer>& layers() const { return layers_; }
+ uint32_t display_id() const { return display_id_; }
+ bool removed() const { return removed_; }
private:
+ uint32_t display_id_;
+ bool removed_;
std::vector<HwcLayer> layers_;
FrameStatus status_ = FrameStatus::kUnfinished;
};
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 10588b7..72a2c26 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -15,12 +15,6 @@
namespace {
-constexpr float kLayerScaleFactor = 4.0f;
-
-constexpr unsigned int kVRAppLayerCount = 2;
-
-constexpr unsigned int kMaximumPendingFrames = 8;
-
const std::string kVertexShader = SHADER0([]() {
layout(location = 0) in vec4 aPosition;
layout(location = 1) in vec4 aTexCoord;
@@ -79,40 +73,6 @@
void main() { fragColor = vec4(0.8, 0.2, 0.2, 1.0); }
});
-const GLfloat kVertices[] = {
- -1, -1, 0,
- 1, -1, 0,
- -1, 1, 0,
- 1, 1, 0,
-};
-
-const GLfloat kTextureVertices[] = {
- 0, 1,
- 1, 1,
- 0, 0,
- 1, 0,
-};
-
-// Returns true if the given point is inside the given rect.
-bool IsInside(const vec2& pt, const vec2& tl, const vec2& br) {
- return pt.x() >= tl.x() && pt.x() <= br.x() &&
- pt.y() >= tl.y() && pt.y() <= br.y();
-}
-
-mat4 GetScalingMatrix(float width, float height) {
- float xscale = 1, yscale = 1;
- float ar = width / height;
- if (ar > 1)
- yscale = 1.0 / ar;
- else
- xscale = ar;
-
- xscale *= kLayerScaleFactor;
- yscale *= kLayerScaleFactor;
-
- return mat4(Eigen::Scaling<float>(xscale, yscale, 1.0));
-}
-
mat4 GetHorizontallyAlignedMatrixFromPose(const Posef& pose) {
vec3 position = pose.GetPosition();
quat view_quaternion = pose.GetRotation();
@@ -131,115 +91,16 @@
m(3, 0) = 0.0f; m(3, 1) = 0.0f; m(3, 2) = 0.0f; m(3, 3) = 1.0f;
// clang-format on
- return m * Eigen::AngleAxisf(M_PI * 0.5f, vec3::UnitZ());
+ return m;
}
-// Helper function that applies the crop transform to the texture layer and
-// positions (and scales) the texture layer in the appropriate location in the
-// display space.
-mat4 GetLayerTransform(const TextureLayer& texture_layer, float display_width,
- float display_height) {
- // Map from vertex coordinates to [0, 1] coordinates:
- // 1) Flip y since in vertex coordinates (-1, -1) is at the bottom left and
- // in texture coordinates (0, 0) is at the top left.
- // 2) Translate by (1, 1) to map vertex coordinates to [0, 2] on x and y.
- // 3) Scale by 1 / 2 to map coordinates to [0, 1] on x and y.
- mat4 unit_space(
- Eigen::AlignedScaling3f(0.5f, 0.5f, 1.0f) *
- Eigen::Translation3f(1.0f, 1.0f, 0.0f) *
- Eigen::AlignedScaling3f(1.0f, -1.0f, 1.0f));
-
- mat4 texture_space(Eigen::AlignedScaling3f(
- texture_layer.texture->width(), texture_layer.texture->height(), 1.0f));
-
- // 1) Translate the layer to crop the left and top edge.
- // 2) Scale the layer such that the cropped right and bottom edges map outside
- // the exture region.
- float crop_width = texture_layer.crop.right - texture_layer.crop.left;
- float crop_height = texture_layer.crop.bottom - texture_layer.crop.top;
- mat4 texture_crop(
- Eigen::AlignedScaling3f(
- texture_layer.texture->width() / crop_width,
- texture_layer.texture->height() / crop_height,
- 1.0f) *
- Eigen::Translation3f(
- -texture_layer.crop.left, -texture_layer.crop.top, 0.0f));
-
- mat4 display_space(
- Eigen::AlignedScaling3f(display_width, display_height, 1.0f));
-
- // 1) Scale the texture to fit the display frame.
- // 2) Translate the texture in the display frame location.
- float display_frame_width = texture_layer.display_frame.right -
- texture_layer.display_frame.left;
- float display_frame_height = texture_layer.display_frame.bottom -
- texture_layer.display_frame.top;
- mat4 display_frame(
- Eigen::Translation3f(
- texture_layer.display_frame.left,
- texture_layer.display_frame.top,
- 0.0f) *
- Eigen::AlignedScaling3f(
- display_frame_width / display_width,
- display_frame_height / display_height,
- 1.0f));
-
- mat4 layer_transform = unit_space.inverse() * display_space.inverse() *
- display_frame * display_space * texture_space.inverse() * texture_crop *
- texture_space * unit_space;
- return layer_transform;
+int GetTouchIdForDisplay(uint32_t display) {
+ return display == 1 ? VirtualTouchpad::PRIMARY : VirtualTouchpad::VIRTUAL;
}
-// Determine if ths frame should be shown or hidden.
-ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
- uint32_t vr_app) {
- auto& layers = frame.layers();
-
- // We assume the first two layers are the VR app. In the case of a 2D app,
- // there will be the app + at least one system layer so this is still safe.
- if (layers.size() < kVRAppLayerCount)
- return ViewMode::Hidden;
-
- if (vr_app != layers[0].appid || layers[0].appid == 0 ||
- layers[1].appid != layers[0].appid) {
- if (layers[1].appid != layers[0].appid && layers[0].appid) {
- // This might be a 2D app.
- // If a dim layer exists afterwards it is much more likely that this is
- // actually an app launch artifact.
- for (size_t i = 2; i < layers.size(); i++) {
- if (layers[i].is_extra_layer())
- return ViewMode::Hidden;
- }
- return ViewMode::App;
- }
- return ViewMode::Hidden;
- }
-
- size_t index = kVRAppLayerCount;
- // Now, find a dim layer if it exists.
- // If it does, ignore any layers behind it for visibility determination.
- for (size_t i = index; i < layers.size(); i++) {
- if (layers[i].appid == HwcCallback::HwcLayer::kSurfaceFlingerLayer) {
- index = i + 1;
- }
- }
-
- // If any non-skipped layers exist now then we show, otherwise hide.
- for (size_t i = index; i < layers.size(); i++) {
- if (!layers[i].should_skip_layer())
- return ViewMode::VR;
- }
- return ViewMode::Hidden;
-}
-
-
} // namespace
-ShellView::ShellView() {
- ime_translate_ = mat4(Eigen::Translation3f(0.0f, -0.5f, 0.25f));
- ime_top_left_ = vec2(0, 0);
- ime_size_ = vec2(0, 0);
-}
+ShellView::ShellView() {}
ShellView::~ShellView() {}
@@ -248,8 +109,6 @@
if (ret)
return ret;
- translate_ = Eigen::Translation3f(0, 0, -2.5f);
-
virtual_touchpad_ = VirtualTouchpadClient::Create();
const status_t touchpad_status = virtual_touchpad_->Attach();
if (touchpad_status != OK) {
@@ -286,6 +145,9 @@
controller_mesh_->SetVertices(kNumControllerMeshVertices,
kControllerMeshVertices);
+ for (auto& display : displays_)
+ display->SetPrograms(program_.get(), overlay_program_.get());
+
initialized_ = true;
return 0;
@@ -302,13 +164,13 @@
}
void ShellView::EnableDebug(bool debug) {
- ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete
+ ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete
QueueTask(debug ? MainThreadTask::EnableDebugMode
: MainThreadTask::DisableDebugMode);
}
void ShellView::VrMode(bool mode) {
- ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete
+ ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete
QueueTask(mode ? MainThreadTask::EnteringVrMode
: MainThreadTask::ExitingVrMode);
}
@@ -320,63 +182,114 @@
result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false");
}
-void ShellView::AdvanceFrame() {
- if (!pending_frames_.empty()) {
- // Check if we should advance the frame.
- auto& frame = pending_frames_.front();
- if (frame.visibility == ViewMode::Hidden ||
- frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
- current_frame_ = std::move(frame);
- pending_frames_.pop_front();
- }
- }
-}
-
void ShellView::OnDrawFrame() {
- textures_.clear();
- has_ime_ = false;
+ bool visible = false;
{
- std::unique_lock<std::mutex> l(pending_frame_mutex_);
- AdvanceFrame();
- }
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
- bool visible = current_frame_.visibility != ViewMode::Hidden;
+ // Move any new displays into the list.
+ if (!new_displays_.empty()) {
+ for (auto& display : new_displays_) {
+ display->Recenter(GetHorizontallyAlignedMatrixFromPose(last_pose_));
+ display->SetPrograms(program_.get(), overlay_program_.get());
+ displays_.emplace_back(display.release());
+ }
+ new_displays_.clear();
+ }
+
+ // Remove any old displays from the list now.
+ if (!removed_displays_.empty()) {
+ for (auto& display : removed_displays_) {
+ displays_.erase(std::find_if(
+ displays_.begin(), displays_.end(),
+ [display](auto& ptr) { return display == ptr.get(); }));
+ }
+ removed_displays_.clear();
+ }
+
+ for (auto& display : displays_) {
+ display->AdvanceFrame();
+ visible = visible || display->visible();
+ }
+ }
if (!debug_mode_ && visible != is_visible_) {
- SetVisibility(current_frame_.visibility != ViewMode::Hidden);
+ SetVisibility(visible);
}
- if (!debug_mode_ && !visible)
- return;
-
- ime_texture_ = TextureLayer();
-
- surface_flinger_view_->GetTextures(*current_frame_.frame.get(), &textures_,
- &ime_texture_, debug_mode_,
- current_frame_.visibility == ViewMode::VR);
- has_ime_ = ime_texture_.texture != nullptr;
+ for (auto& display : displays_) {
+ display->OnDrawFrame(surface_flinger_view_.get(), debug_mode_);
+ }
}
-void ShellView::DrawEye(EyeType /* eye */, const mat4& perspective,
+void ShellView::OnEndFrame() {
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
+ for (auto& display : displays_) {
+ display->UpdateReleaseFence();
+ }
+}
+
+DisplayView* ShellView::FindOrCreateDisplay(uint32_t id) {
+ for (auto& display : displays_) {
+ if (display->id() == id) {
+ return display.get();
+ }
+ }
+
+ // It might be pending addition.
+ for (auto& display : new_displays_) {
+ if (display->id() == id) {
+ return display.get();
+ }
+ }
+
+ auto display = new DisplayView(id, GetTouchIdForDisplay(id));
+ new_displays_.emplace_back(display);
+ return display;
+}
+
+base::unique_fd ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
+ DisplayView* display = FindOrCreateDisplay(frame->display_id());
+
+ if (frame->removed()) {
+ removed_displays_.push_back(display);
+ return base::unique_fd();
+ }
+
+ bool showing = false;
+
+ base::unique_fd fd(display->OnFrame(std::move(frame), debug_mode_, &showing));
+
+ if (showing)
+ QueueTask(MainThreadTask::Show);
+
+ return fd;
+}
+
+void ShellView::DrawEye(EyeType eye, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix) {
- if (should_recenter_) {
+ if (should_recenter_ && !displays_.empty()) {
// Position the quad horizontally aligned in the direction the user
// is facing, effectively taking out head roll.
- initial_head_matrix_ = GetHorizontallyAlignedMatrixFromPose(last_pose_);
+ displays_[0]->Recenter(GetHorizontallyAlignedMatrixFromPose(last_pose_));
should_recenter_ = false;
}
size_ = vec2(surface_flinger_view_->width(), surface_flinger_view_->height());
- scale_ = GetScalingMatrix(size_.x(), size_.y());
-
- DrawOverlays(perspective, eye_matrix, head_matrix);
// TODO(alexst): Replicate controller rendering from VR Home.
// Current approach in the function below is a quick visualization.
DrawController(perspective, eye_matrix, head_matrix);
- // TODO: Make sure reticle is shown only over visible overlays.
+ for (auto& display : displays_) {
+ if (display->visible()) {
+ display->DrawEye(eye, perspective, eye_matrix, head_matrix, size_,
+ fade_value_);
+ }
+ }
+
DrawReticle(perspective, eye_matrix, head_matrix);
}
@@ -387,7 +300,7 @@
bool ShellView::OnClick(bool down) {
if (down) {
- if (!is_touching_ && allow_input_) {
+ if (!is_touching_ && active_display_ && active_display_->allow_input()) {
is_touching_ = true;
}
} else {
@@ -397,224 +310,6 @@
return true;
}
-base::unique_fd ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
- ViewMode visibility =
- CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
-
- if (visibility == ViewMode::Hidden && debug_mode_)
- visibility = ViewMode::VR;
-
- if (frame->layers().empty())
- current_vr_app_ = 0;
- else
- current_vr_app_ = frame->layers().front().appid;
-
- std::unique_lock<std::mutex> l(pending_frame_mutex_);
-
- pending_frames_.emplace_back(std::move(frame), visibility);
-
- if (pending_frames_.size() > kMaximumPendingFrames) {
- pending_frames_.pop_front();
- }
-
- if (visibility == ViewMode::Hidden &&
- current_frame_.visibility == ViewMode::Hidden) {
- // Consume all frames while hidden.
- while (!pending_frames_.empty())
- AdvanceFrame();
- }
-
- // If we are showing ourselves the main thread is not processing anything,
- // so give it a kick.
- if (visibility != ViewMode::Hidden &&
- current_frame_.visibility == ViewMode::Hidden) {
- QueueTask(MainThreadTask::Show);
- }
-
- return base::unique_fd(dup(release_fence_.get()));
-}
-
-bool ShellView::IsHit(const vec3& view_location, const vec3& view_direction,
- vec3* hit_location, vec2* hit_location_in_window_coord,
- bool test_ime) {
- mat4 m = initial_head_matrix_ * translate_;
- if (test_ime)
- m = m * ime_translate_;
- mat4 inverse = (m * scale_).inverse();
- vec4 transformed_loc =
- inverse * vec4(view_location[0], view_location[1], view_location[2], 1);
- vec4 transformed_dir = inverse * vec4(view_direction[0], view_direction[1],
- view_direction[2], 0);
-
- if (transformed_dir.z() >= 0 || transformed_loc.z() <= 0)
- return false;
-
- float distance = -transformed_loc.z() / transformed_dir.z();
- vec4 transformed_hit_loc = transformed_loc + transformed_dir * distance;
- if (transformed_hit_loc.x() < -1 || transformed_hit_loc.x() > 1)
- return false;
- if (transformed_hit_loc.y() < -1 || transformed_hit_loc.y() > 1)
- return false;
-
- hit_location_in_window_coord->x() =
- (1 + transformed_hit_loc.x()) / 2 * size_.x();
- hit_location_in_window_coord->y() =
- (1 - transformed_hit_loc.y()) / 2 * size_.y();
-
- *hit_location = view_location + view_direction * distance;
- return true;
-}
-
-void ShellView::DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
- const mat4& head_matrix) {
- if (textures_.empty())
- return;
-
- program_->Use();
- mat4 mvp = perspective * eye_matrix * head_matrix;
- GLint view_projection_location =
- glGetUniformLocation(program_->GetProgram(), "uViewProjection");
- glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data());
-
- GLint alpha_location =
- glGetUniformLocation(program_->GetProgram(), "uAlpha");
-
- GLint tex_location = glGetUniformLocation(program_->GetProgram(), "tex");
- glUniform1i(tex_location, 0);
- glActiveTexture(GL_TEXTURE0);
-
- for (const auto& texture_layer : textures_) {
- switch (texture_layer.blending) {
- case HWC2_BLEND_MODE_PREMULTIPLIED:
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- break;
- case HWC2_BLEND_MODE_COVERAGE:
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- break;
- default:
- break;
- }
-
- glUniform1f(alpha_location, fade_value_ * texture_layer.alpha);
-
- glBindTexture(GL_TEXTURE_2D, texture_layer.texture->id());
-
- mat4 layer_transform = GetLayerTransform(texture_layer, size_.x(),
- size_.y());
-
- mat4 transform = initial_head_matrix_ * translate_ * scale_ *
- layer_transform;
- DrawWithTransform(transform, *program_);
-
- glDisable(GL_BLEND);
- }
-
- if (has_ime_) {
- ime_top_left_ = vec2(static_cast<float>(ime_texture_.display_frame.left),
- static_cast<float>(ime_texture_.display_frame.top));
- ime_size_ = vec2(static_cast<float>(ime_texture_.display_frame.right -
- ime_texture_.display_frame.left),
- static_cast<float>(ime_texture_.display_frame.bottom -
- ime_texture_.display_frame.top));
-
- DrawDimOverlay(mvp, textures_[0], ime_top_left_, ime_top_left_ + ime_size_);
-
- 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() {
- program_->Use();
- glBindTexture(GL_TEXTURE_2D, ime_texture_.texture->id());
-
- mat4 layer_transform = GetLayerTransform(ime_texture_, size_.x(), size_.y());
-
- mat4 transform = initial_head_matrix_ * translate_ * ime_translate_ * scale_ *
- layer_transform;
-
- DrawWithTransform(transform, *program_);
-}
-
-void ShellView::DrawDimOverlay(const mat4& mvp, const TextureLayer& layer, const vec2& top_left,
- const vec2& bottom_right) {
- overlay_program_->Use();
- glUniformMatrix4fv(
- glGetUniformLocation(overlay_program_->GetProgram(), "uViewProjection"),
- 1, 0, mvp.data());
- glUniform4f(glGetUniformLocation(overlay_program_->GetProgram(), "uCoords"),
- top_left.x() / size_.x(), top_left.y() / size_.y(),
- bottom_right.x() / size_.x(), bottom_right.y() / size_.y());
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- mat4 layer_transform =
- GetLayerTransform(layer, size_.x(), size_.y());
-
- mat4 transform =
- initial_head_matrix_ * translate_ * scale_ * layer_transform;
- DrawWithTransform(transform, *overlay_program_);
- glDisable(GL_BLEND);
-}
-
-void ShellView::DrawWithTransform(const mat4& transform,
- const ShaderProgram& program) {
- GLint transform_location =
- glGetUniformLocation(program.GetProgram(), "uTransform");
- glUniformMatrix4fv(transform_location, 1, 0, transform.data());
-
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, kVertices);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kTextureVertices);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-}
-
-bool ShellView::IsImeHit(const vec3& view_location, const vec3& view_direction,
- vec3 *hit_location) {
- // First, check if the IME window is hit.
- bool is_hit = IsHit(view_location, view_direction, hit_location,
- &hit_location_in_window_coord_, true);
- if (is_hit) {
- // If it is, check if the window coordinate is in the IME region;
- // if so then we are done.
- if (IsInside(hit_location_in_window_coord_, ime_top_left_,
- ime_top_left_ + ime_size_)) {
- allow_input_ = true;
- return true;
- }
- }
-
- allow_input_ = false;
- // Check if we have hit the main window.
- is_hit = IsHit(view_location, view_direction, hit_location,
- &hit_location_in_window_coord_, false);
- if (is_hit) {
- // Only allow input if we are not hitting the region hidden by the IME.
- // Allowing input here would cause clicks on the main window to actually
- // be clicks on the IME.
- if (!IsInside(hit_location_in_window_coord_, ime_top_left_,
- ime_top_left_ + ime_size_)) {
- allow_input_ = true;
- }
- }
- return is_hit;
-}
-
void ShellView::DrawReticle(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) {
reticle_->Hide();
@@ -653,30 +348,47 @@
}
}
- vec3 view_direction = vec3(view_quaternion * vec3(0, 0, -1));
-
vec3 hit_location;
+ active_display_ =
+ FindActiveDisplay(pointer_location, view_quaternion, &hit_location);
- bool is_hit;
- if(has_ime_) {
- // This will set allow_input_ and hit_location_in_window_coord_.
- is_hit = IsImeHit(pointer_location, view_direction, &hit_location);
- } else {
- is_hit = IsHit(pointer_location, view_direction, &hit_location,
- &hit_location_in_window_coord_, false);
- allow_input_ = is_hit;
- }
-
- if (is_hit) {
+ if (active_display_) {
reticle_->ShowAt(
Eigen::Translation3f(hit_location) * view_quaternion.matrix(),
- allow_input_ ? vec3(1, 0, 0) : vec3(0, 0, 0));
+ active_display_->allow_input() ? vec3(1, 0, 0) : vec3(0, 0, 0));
Touch();
}
reticle_->Draw(perspective, eye_matrix, head_matrix);
}
+DisplayView* ShellView::FindActiveDisplay(const vec3& position,
+ const quat& quaternion,
+ vec3* hit_location) {
+ vec3 direction = vec3(quaternion * vec3(0, 0, -1));
+ vec3 temp_hit;
+
+ DisplayView* best_display = nullptr;
+ vec3 best_hit;
+
+ auto is_better = [&best_hit, &position](DisplayView*, const vec3& hit) {
+ return (hit - position).squaredNorm() < (best_hit - position).squaredNorm();
+ };
+
+ for (auto& display : displays_) {
+ if (display->UpdateHitInfo(position, direction, &temp_hit)) {
+ if (!best_display || is_better(display.get(), temp_hit)) {
+ best_display = display.get();
+ best_hit = temp_hit;
+ }
+ }
+ }
+
+ if (best_display)
+ *hit_location = best_hit;
+ return best_display;
+}
+
void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) {
if (!shmem_controller_active_)
@@ -712,10 +424,16 @@
return;
}
+ if (!active_display_)
+ return;
+
+ const vec2& hit_location = active_display_->hit_location();
+
+ // Device is portrait, but in landscape when in VR.
+ // Rotate touch input appropriately.
const android::status_t status = virtual_touchpad_->Touch(
- VirtualTouchpad::PRIMARY,
- hit_location_in_window_coord_.x() / size_.x(),
- hit_location_in_window_coord_.y() / size_.y(),
+ active_display_->touchpad_id(),
+ 1.0f - hit_location.y() / size_.y(), hit_location.x() / size_.x(),
is_touching_ ? 1.0f : 0.0f);
if (status != OK) {
ALOGE("touch failed: %d", status);
@@ -725,7 +443,7 @@
bool ShellView::OnTouchpadButton(bool down, int button) {
int buttons = touchpad_buttons_;
if (down) {
- if (allow_input_) {
+ if (active_display_ && active_display_->allow_input()) {
buttons |= button;
}
} else {
@@ -740,18 +458,16 @@
return false;
}
+ if (!active_display_)
+ return true;
+
const android::status_t status = virtual_touchpad_->ButtonState(
- VirtualTouchpad::PRIMARY, touchpad_buttons_);
+ active_display_->touchpad_id(), touchpad_buttons_);
if (status != OK) {
ALOGE("touchpad button failed: %d %d", touchpad_buttons_, status);
}
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 49456c6..c10bd27 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -8,6 +8,7 @@
#include "VirtualTouchpadClient.h"
#include "application.h"
+#include "display_view.h"
#include "reticle.h"
#include "shell_view_binder_interface.h"
#include "surface_flinger_view.h"
@@ -15,12 +16,6 @@
namespace android {
namespace dvr {
-enum class ViewMode {
- Hidden,
- VR,
- App,
-};
-
class ShellView : public Application,
public android::dvr::ShellViewBinderInterface,
public HwcCallback::Client {
@@ -41,91 +36,54 @@
protected:
void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) override;
+ void OnDrawFrame() override;
+ void OnEndFrame() override;
void OnVisibilityChanged(bool visible) override;
- void DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
- const mat4& head_matrix);
void DrawReticle(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix);
- void DrawIme();
- void DrawDimOverlay(const mat4& mvp, const TextureLayer& layer,
- const vec2& top_left, const vec2& bottom_right);
void DrawController(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix);
- bool IsHit(const vec3& view_location, const vec3& view_direction,
- vec3* hit_location, vec2* hit_location_in_window_coord,
- bool test_ime);
- bool IsImeHit(const vec3& view_location, const vec3& view_direction,
- vec3 *hit_location);
void Touch();
bool OnTouchpadButton(bool down, int button);
- void OnDrawFrame() override;
- void DrawWithTransform(const mat4& transform, const ShaderProgram& program);
-
bool OnClick(bool down);
- void AdvanceFrame();
+ DisplayView* FindActiveDisplay(const vec3& position, const quat& quaternion,
+ vec3* hit_location);
- void UpdateReleaseFence(base::unique_fd fence);
// HwcCallback::Client:
base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
+ DisplayView* FindOrCreateDisplay(uint32_t id);
std::unique_ptr<ShaderProgram> program_;
std::unique_ptr<ShaderProgram> overlay_program_;
std::unique_ptr<ShaderProgram> controller_program_;
- uint32_t current_vr_app_;
-
- // Used to center the scene when the shell becomes visible.
- bool should_recenter_ = true;
- mat4 initial_head_matrix_;
- mat4 scale_;
- mat4 translate_;
- mat4 ime_translate_;
- vec2 size_;
-
std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
std::unique_ptr<Reticle> reticle_;
sp<VirtualTouchpad> virtual_touchpad_;
- std::vector<TextureLayer> textures_;
- TextureLayer ime_texture_;
-
- bool is_touching_ = false;
- bool allow_input_ = false;
- int touchpad_buttons_ = 0;
- vec2 hit_location_in_window_coord_;
- vec2 ime_top_left_;
- vec2 ime_size_;
- bool has_ime_ = false;
std::unique_ptr<Mesh<vec3, vec3, vec2>> controller_mesh_;
- struct PendingFrame {
- PendingFrame() = default;
- PendingFrame(std::unique_ptr<HwcCallback::Frame>&& frame, ViewMode visibility)
- : frame(std::move(frame)), visibility(visibility) {}
- PendingFrame(PendingFrame&& r)
- : frame(std::move(r.frame)), visibility(r.visibility) {}
+ bool is_touching_ = false;
+ int touchpad_buttons_ = 0;
+ vec2 size_;
- void operator=(PendingFrame&& r) {
- frame.reset(r.frame.release());
- visibility = r.visibility;
- }
+ // Used to center the scene when the shell becomes visible.
+ bool should_recenter_ = true;
- std::unique_ptr<HwcCallback::Frame> frame;
- ViewMode visibility = ViewMode::Hidden;
- };
- std::deque<PendingFrame> pending_frames_;
- std::mutex pending_frame_mutex_;
- PendingFrame current_frame_;
+ std::mutex display_frame_mutex_;
+
+ std::vector<std::unique_ptr<DisplayView>> displays_;
+ std::vector<std::unique_ptr<DisplayView>> new_displays_;
+ std::vector<DisplayView*> removed_displays_;
+ DisplayView* active_display_ = nullptr;
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 63bc143..2011967 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -54,9 +54,7 @@
size_t start = 0;
// Skip the second layer if it is from the VR app.
if (!debug && skip_first_layer) {
- start = 1;
- if (layers[0].appid && layers[0].appid == layers[1].appid)
- start = 2;
+ start = 2;
}
for (size_t i = start; i < layers.size(); ++i) {
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index ba3cf79..3f077a2 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -16,7 +16,10 @@
name: "libvulkan_headers",
from: "include",
to: "",
- srcs: ["include/vulkan/**/*.h"],
+ srcs: [
+ "include/vulkan/vk_platform.h",
+ "include/vulkan/vulkan.h",
+ ],
license: "include/vulkan/NOTICE",
}
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index b4708b0..86dd001 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -320,6 +320,10 @@
@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"
+// 119
+@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
+@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
+
// 123
@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_SPEC_VERSION 1
@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
@@ -1082,6 +1086,14 @@
//@extension("VK_EXT_hdr_metadata") // 106
VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
+ //@extension("VK_KHR_shared_presentable_image") // 111
+ VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
+
+ //@extension("VK_KHR_get_surface_capabilities2") // 119
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
+ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
+ VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
+
//@extension("VK_MVK_ios_surface") // 123
VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
@@ -4245,6 +4257,34 @@
f32 maxFrameAverageLightLevel
}
+@extension("VK_KHR_shared_presentable_image") // 111
+class VkSharedPresentSurfaceCapabilitiesKHR {
+ VkStructureType sType
+ const void* pNext
+ VkImageUsageFlags sharedPresentSupportedUsageFlags
+}
+
+@extension("VK_KHR_get_surface_capabilities2") // 119
+class VkPhysicalDeviceSurfaceInfo2KHR {
+ VkStructureType sType
+ const void* pNext
+ VkSurfaceKHR surface
+}
+
+@extension("VK_KHR_get_surface_capabilities2") // 119
+class VkSurfaceCapabilities2KHR {
+ VkStructureType sType
+ void* pNext
+ VkSurfaceCapabilitiesKHR surfaceCapabilities
+}
+
+@extension("VK_KHR_get_surface_capabilities2") // 119
+class VkSurfaceFormat2KHR {
+ VkStructureType sType
+ void* pNext
+ VkSurfaceFormatKHR surfaceFormat
+}
+
@extension("VK_MVK_ios_surface") // 123
class VkIOSSurfaceCreateInfoMVK {
VkStructureType sType
@@ -7418,6 +7458,23 @@
return ?
}
+@extension("VK_KHR_get_surface_capabilities2") // 119
+cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
+ return ?
+}
+
+@extension("VK_KHR_get_surface_capabilities2") // 119
+cmd VkResult vkGetPhysicalDeviceSurfaceFormats2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ u32* pSurfaceFormatCount,
+ VkSurfaceFormat2KHR* pSurfaceFormats) {
+ return ?
+}
+
@extension("VK_MVK_ios_surface") // 123
cmd VkResult vkCreateIOSSurfaceMVK(
VkInstance instance,
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 8bb5448..2293960 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -301,6 +301,10 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,
VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
+ VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
+ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
+ VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
@@ -5766,6 +5770,13 @@
#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
+typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ VkImageUsageFlags sharedPresentSupportedUsageFlags;
+} VkSharedPresentSurfaceCapabilitiesKHR;
+
+
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
#ifndef VK_NO_PROTOTYPES
@@ -5774,6 +5785,46 @@
VkSwapchainKHR swapchain);
#endif
+#define VK_KHR_get_surface_capabilities2 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
+
+typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSurfaceKHR surface;
+} VkPhysicalDeviceSurfaceInfo2KHR;
+
+typedef struct VkSurfaceCapabilities2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkSurfaceCapabilitiesKHR surfaceCapabilities;
+} VkSurfaceCapabilities2KHR;
+
+typedef struct VkSurfaceFormat2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkSurfaceFormatKHR surfaceFormat;
+} VkSurfaceFormat2KHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ uint32_t* pSurfaceFormatCount,
+ VkSurfaceFormat2KHR* pSurfaceFormats);
+#endif
+
+
#ifdef VK_USE_PLATFORM_IOS_MVK
#define VK_MVK_ios_surface 1
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 69e38de..54c77f1 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -110,7 +110,7 @@
// clang-format on
-} // anonymous
+} // namespace
bool InitDispatchTable(
VkInstance instance,
@@ -473,7 +473,9 @@
"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
"vkGetPhysicalDeviceSparseImageFormatProperties",
"vkGetPhysicalDeviceSparseImageFormatProperties2KHR",
+ "vkGetPhysicalDeviceSurfaceCapabilities2KHR",
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
+ "vkGetPhysicalDeviceSurfaceFormats2KHR",
"vkGetPhysicalDeviceSurfaceFormatsKHR",
"vkGetPhysicalDeviceSurfacePresentModesKHR",
"vkGetPhysicalDeviceSurfaceSupportKHR",
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 7f8d274..3e50fda 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -19,8 +19,8 @@
#ifndef LIBVULKAN_API_GEN_H
#define LIBVULKAN_API_GEN_H
-#include <bitset>
#include <vulkan/vulkan.h>
+#include <bitset>
#include "driver_gen.h"
namespace vulkan {
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 185121c..5bbe116 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -690,6 +690,7 @@
VK_KHR_shared_presentable_image
VK_KHR_surface
VK_KHR_swapchain
+VK_KHR_get_surface_capabilities2
{{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index b62eec6..dbb217d 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -448,6 +448,7 @@
case ProcHook::KHR_android_surface:
case ProcHook::KHR_surface:
case ProcHook::EXT_swapchain_colorspace:
+ case ProcHook::KHR_get_surface_capabilities2:
hook_extensions_.set(ext_bit);
// return now as these extensions do not require HAL support
return;
@@ -674,13 +675,15 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
- static const std::array<VkExtensionProperties, 3> loader_extensions = {{
+ static const std::array<VkExtensionProperties, 4> loader_extensions = {{
// WSI extensions
{VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
{VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
{VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION},
+ {VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION},
}};
static const VkExtensionProperties loader_debug_report_extension = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index fc3f87a..82b464e 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -262,6 +262,13 @@
reinterpret_cast<PFN_vkVoidFunction>(checkedGetPastPresentationTimingGOOGLE),
},
{
+ "vkGetPhysicalDeviceSurfaceCapabilities2KHR",
+ ProcHook::INSTANCE,
+ ProcHook::KHR_get_surface_capabilities2,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilities2KHR),
+ nullptr,
+ },
+ {
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
ProcHook::INSTANCE,
ProcHook::KHR_surface,
@@ -269,6 +276,13 @@
nullptr,
},
{
+ "vkGetPhysicalDeviceSurfaceFormats2KHR",
+ ProcHook::INSTANCE,
+ ProcHook::KHR_get_surface_capabilities2,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormats2KHR),
+ nullptr,
+ },
+ {
"vkGetPhysicalDeviceSurfaceFormatsKHR",
ProcHook::INSTANCE,
ProcHook::KHR_surface,
@@ -348,7 +362,7 @@
// clang-format on
};
-} // anonymous
+} // namespace
const ProcHook* GetProcHook(const char* name) {
const auto& begin = g_proc_hooks;
@@ -372,6 +386,7 @@
if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
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_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 738da5b..3b26a80 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -19,9 +19,9 @@
#ifndef LIBVULKAN_DRIVER_GEN_H
#define LIBVULKAN_DRIVER_GEN_H
-#include <bitset>
-#include <vulkan/vulkan.h>
#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+#include <bitset>
namespace vulkan {
namespace driver {
@@ -43,6 +43,7 @@
KHR_shared_presentable_image,
KHR_surface,
KHR_swapchain,
+ KHR_get_surface_capabilities2,
KHR_get_physical_device_properties2,
EXTENSION_CORE, // valid bit
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a0ae1f3..b24bc1b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -17,7 +17,7 @@
#include <algorithm>
#include <log/log.h>
-#include <gui/BufferQueue.h>
+#include <ui/BufferQueueDefs.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
@@ -207,7 +207,7 @@
// or by passing ownership e.g. to ANativeWindow::cancelBuffer().
int dequeue_fence;
bool dequeued;
- } images[android::BufferQueue::NUM_BUFFER_SLOTS];
+ } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
android::Vector<TimingInfo> timing;
};
@@ -649,6 +649,72 @@
}
VKAPI_ATTR
+VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
+ VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR(
+ physicalDevice, pSurfaceInfo->surface,
+ &pSurfaceCapabilities->surfaceCapabilities);
+
+ VkSurfaceCapabilities2KHR* caps = pSurfaceCapabilities;
+ while (caps->pNext) {
+ caps = reinterpret_cast<VkSurfaceCapabilities2KHR*>(caps->pNext);
+
+ switch (caps->sType) {
+ case VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR: {
+ VkSharedPresentSurfaceCapabilitiesKHR* shared_caps =
+ reinterpret_cast<VkSharedPresentSurfaceCapabilitiesKHR*>(
+ caps);
+ // Claim same set of usage flags are supported for
+ // shared present modes as for other modes.
+ shared_caps->sharedPresentSupportedUsageFlags =
+ pSurfaceCapabilities->surfaceCapabilities
+ .supportedUsageFlags;
+ } break;
+
+ default:
+ // Ignore all other extension structs
+ break;
+ }
+ }
+
+ return result;
+}
+
+VKAPI_ATTR
+VkResult GetPhysicalDeviceSurfaceFormats2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ uint32_t* pSurfaceFormatCount,
+ VkSurfaceFormat2KHR* pSurfaceFormats) {
+ if (!pSurfaceFormats) {
+ return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
+ pSurfaceInfo->surface,
+ pSurfaceFormatCount, nullptr);
+ } else {
+ // temp vector for forwarding; we'll marshal it into the pSurfaceFormats
+ // after the call.
+ android::Vector<VkSurfaceFormatKHR> surface_formats;
+ surface_formats.resize(*pSurfaceFormatCount);
+ VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
+ physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
+ &surface_formats.editItemAt(0));
+
+ if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
+ // marshal results individually due to stride difference.
+ // completely ignore any chained extension structs.
+ uint32_t formats_to_marshal = *pSurfaceFormatCount;
+ for (uint32_t i = 0u; i < formats_to_marshal; i++) {
+ pSurfaceFormats[i].surfaceFormat = surface_formats[i];
+ }
+ }
+
+ return result;
+ }
+}
+
+VKAPI_ATTR
VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
VkSurfaceKHR /*surface*/,
uint32_t* count,
@@ -903,8 +969,7 @@
int gralloc_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
- uint32_t driver_version = GetData(device).driver_version;
- if (driver_version == 256587285 || driver_version == 96011958) {
+ if (GetData(device).driver_version == 256587285) {
// HACK workaround for loader/driver mismatch during transition to
// vkGetSwapchainGrallocUsage2ANDROID.
typedef VkResult(VKAPI_PTR *
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index 976c995..e3cf624 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -38,6 +38,8 @@
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);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
// clang-format on
} // namespace driver
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index e03ee0a..6714779 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -513,6 +513,28 @@
void GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physical_device,
VkPhysicalDeviceProperties2KHR* properties) {
GetPhysicalDeviceProperties(physical_device, &properties->properties);
+
+ while (properties->pNext) {
+ properties = reinterpret_cast<VkPhysicalDeviceProperties2KHR *>(properties->pNext);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ switch ((VkFlags)properties->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID: {
+ VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties =
+ reinterpret_cast<VkPhysicalDevicePresentationPropertiesANDROID *>(properties);
+#pragma clang diagnostic pop
+
+ // Claim that we do all the right things for the loader to
+ // expose KHR_shared_presentable_image on our behalf.
+ presentation_properties->sharedImage = VK_TRUE;
+ } break;
+
+ default:
+ // Silently ignore other extension query structs
+ break;
+ }
+ }
}
void GetPhysicalDeviceQueueFamilyProperties(
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index 7cbbdb1..25ee65a 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -16,8 +16,8 @@
// WARNING: This file is generated. See ../README.md for instructions.
-#include "null_driver_gen.h"
#include <algorithm>
+#include "null_driver_gen.h"
using namespace null_driver;